← back to index

src/diagnostics/MOM_wave_speed.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
5!> Routines for calculating baroclinic wave speeds
6module MOM_wave_speed
7
8use MOM_diag_mediator, only : post_data, query_averaging_enabled, diag_ctrl
9use MOM_error_handler, only : MOM_error, FATAL, WARNING
10use MOM_file_parser, only : log_version
11use MOM_grid, only : ocean_grid_type
12use MOM_interface_heights, only : thickness_to_dz
13use MOM_remapping, only : remapping_CS, initialize_remapping, remapping_core_h, interpolate_column
14use MOM_unit_scaling, only : unit_scale_type
15use MOM_variables, only : thermo_var_ptrs
16use MOM_verticalGrid, only : verticalGrid_type
17use MOM_EOS, only : calculate_density_derivs, calculate_specific_vol_derivs
18
19implicit none ; private
20
21#include <MOM_memory.h>
22
23public wave_speed, wave_speeds, wave_speed_init, wave_speed_set_param
24
25! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
26! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
27! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
28! vary with the Boussinesq approximation, the Boussinesq variant is given first.
29
30!> Control structure for MOM_wave_speed
31type, public :: wave_speed_CS ; private
32 logical :: initialized = .false. !< True if this control structure has been initialized.
33 logical :: use_ebt_mode = .false. !< If true, calculate the equivalent barotropic wave speed instead
34 !! of the first baroclinic wave speed.
35 !! This parameter controls the default behavior of wave_speed() which
36 !! can be overridden by optional arguments.
37 logical :: better_cg1_est = .false. !< If true, use an improved estimate of the first mode
38 !! internal wave speed.
39 real :: mono_N2_column_fraction = 0. !< The lower fraction of water column over which N2 is limited as
40 !! monotonic for the purposes of calculating the equivalent barotropic
41 !! wave speed [nondim]. This parameter controls the default behavior of
42 !! wave_speed() which can be overridden by optional arguments.
43 real :: mono_N2_depth = -1. !< The depth below which N2 is limited as monotonic for the purposes of
44 !! calculating the equivalent barotropic wave speed [H ~> m or kg m-2].
45 !! If this parameter is negative, this limiting does not occur.
46 !! This parameter controls the default behavior of wave_speed() which
47 !! can be overridden by optional arguments.
48 real :: min_speed2 = 0. !< The minimum mode 1 internal wave speed squared [L2 T-2 ~> m2 s-2]
49 real :: wave_speed_tol = 0.001 !< The fractional tolerance with which to solve for the wave
50 !! speeds [nondim]
51 real :: c1_thresh = -1.0 !< A minimal value of the first mode internal wave speed
52 !! below which all higher mode speeds are not calculated but
53 !! are simply reported as 0 [L T-1 ~> m s-1]. A non-negative
54 !! value must be specified via a call to wave_speed_init for
55 !! the subroutine wave_speeds to be used (but not wave_speed).
56 type(remapping_CS) :: remap_2018_CS !< Used for vertical remapping when calculating equivalent barotropic
57 !! mode structure for answer dates below 20190101.
58 type(remapping_CS) :: remap_CS !< Used for vertical remapping when calculating equivalent barotropic
59 !! mode structure.
60 integer :: remap_answer_date = 99991231 !< The vintage of the order of arithmetic and expressions to use
61 !! for remapping. Values below 20190101 recover the remapping
62 !! answers from 2018, while higher values use more robust
63 !! forms of the same remapping expressions.
64 type(diag_ctrl), pointer :: diag !< Diagnostics control structure
65end type wave_speed_CS
66
67contains
68
69!> Calculates the wave speed of the first baroclinic mode.
7048subroutine wave_speed(h, tv, G, GV, US, cg1, CS, halo_size, use_ebt_mode, mono_N2_column_fraction, &
710 mono_N2_depth, modal_structure)
72 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
73 type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure
74 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
75 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
76 intent(in) :: h !< Layer thickness [H ~> m or kg m-2]
77 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamic variables
78 real, dimension(SZI_(G),SZJ_(G)), intent(out) :: cg1 !< First mode internal wave speed [L T-1 ~> m s-1]
79 type(wave_speed_CS), intent(in) :: CS !< Wave speed control struct
80 integer, optional, intent(in) :: halo_size !< Width of halo within which to
81 !! calculate wave speeds
82 logical, optional, intent(in) :: use_ebt_mode !< If true, use the equivalent
83 !! barotropic mode instead of the first baroclinic mode.
84 real, optional, intent(in) :: mono_N2_column_fraction !< The lower fraction
85 !! of water column over which N2 is limited as monotonic
86 !! for the purposes of calculating vertical modal structure [nondim].
87 real, optional, intent(in) :: mono_N2_depth !< A depth below which N2 is limited as
88 !! monotonic for the purposes of calculating vertical
89 !! modal structure [H ~> m or kg m-2].
90 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
91 optional, intent(out) :: modal_structure !< Normalized model structure [nondim]
92
93 ! Local variables
94 real, dimension(SZK_(GV)+1) :: &
9548 dRho_dT, & ! Partial derivative of density with temperature [R C-1 ~> kg m-3 degC-1]
9648 dRho_dS, & ! Partial derivative of density with salinity [R S-1 ~> kg m-3 ppt-1]
9748 dSpV_dT, & ! Partial derivative of specific volume with temperature [R-1 C-1 ~> m3 kg-1 degC-1]
9848 dSpV_dS, & ! Partial derivative of specific volume with salinity [R-1 S-1 ~> m3 kg-1 ppt-1]
9948 pres, & ! Interface pressure [R L2 T-2 ~> Pa]
10048 T_int, & ! Temperature interpolated to interfaces [C ~> degC]
10148 S_int, & ! Salinity interpolated to interfaces [S ~> ppt]
10248 H_top, & ! The distance of each filtered interface from the ocean surface [H ~> m or kg m-2]
10348 H_bot, & ! The distance of each filtered interface from the bottom [H ~> m or kg m-2]
10448 gprime ! The reduced gravity across each interface [L2 H-1 T-2 ~> m s-2 or m4 s-2 kg-1].
105 real, dimension(SZK_(GV)) :: &
10648 Igl, Igu ! The inverse of the reduced gravity across an interface times
107 ! the thickness of the layer below (Igl) or above (Igu) it, in [T2 L-2 ~> s2 m-2].
108 real, dimension(SZK_(GV),SZI_(G)) :: &
10948 Hf, & ! Layer thicknesses after very thin layers are combined [H ~> m or kg m-2]
11048 Tf, & ! Layer temperatures after very thin layers are combined [C ~> degC]
11148 Sf, & ! Layer salinities after very thin layers are combined [S ~> ppt]
11248 Rf ! Layer densities after very thin layers are combined [R ~> kg m-3]
113 real, dimension(SZK_(GV)) :: &
11448 Hc, & ! A column of layer thicknesses after convective instabilities are removed [H ~> m or kg m-2]
11548 Tc, & ! A column of layer temperatures after convective instabilities are removed [C ~> degC]
11648 Sc, & ! A column of layer salinities after convective instabilities are removed [S ~> ppt]
11748 Rc ! A column of layer densities after convective instabilities are removed [R ~> kg m-3]
118 real :: I_Htot ! The inverse of the total filtered thicknesses [H-1 ~> m-1 or m2 kg-1]
119 real :: det, ddet ! Determinant of the eigen system and its derivative with lam. Because the
120 ! units of the eigenvalue change with the number of layers and because of the
121 ! dynamic rescaling that is used to keep det in a numerically representable range,
122 ! the units of of det are hard to interpret, but det/ddet is always in units
123 ! of [T2 L-2 ~> s2 m-2]
124 real :: lam ! The eigenvalue [T2 L-2 ~> s2 m-2]
125 real :: dlam ! The change in estimates of the eigenvalue [T2 L-2 ~> s2 m-2]
126 real :: lam0 ! The first guess of the eigenvalue [T2 L-2 ~> s2 m-2]
127 real :: H_to_pres ! A conversion factor from thicknesses to pressure [R L2 T-2 H-1 ~> Pa m-1 or Pa m2 kg-1]
128 real, dimension(SZI_(G)) :: &
12948 htot, hmin, & ! Thicknesses [H ~> m or kg m-2]
13048 H_here, & ! A thickness [H ~> m or kg m-2]
13148 HxT_here, & ! A layer integrated temperature [C H ~> degC m or degC kg m-2]
13248 HxS_here, & ! A layer integrated salinity [S H ~> ppt m or ppt kg m-2]
13348 HxR_here ! A layer integrated density [R H ~> kg m-2 or kg2 m-5]
134 real :: speed2_tot ! overestimate of the mode-1 speed squared [L2 T-2 ~> m2 s-2]
135 real :: cg1_min2 ! A floor in the squared first mode speed below which 0 is returned [L2 T-2 ~> m2 s-2]
136 real :: cg1_est ! An initial estimate of the squared first mode speed [L2 T-2 ~> m2 s-2]
137 real :: I_Hnew ! The inverse of a new layer thickness [H-1 ~> m-1 or m2 kg-1]
138 real :: drxh_sum ! The sum of density differences across interfaces times thicknesses [R H ~> kg m-2 or kg2 m-5]
139 real :: dSpVxh_sum ! The sum of specific volume differences across interfaces times
140 ! thicknesses [H R-1 ~> m4 kg-1 or m], negative for stable stratification.
141 real :: g_Rho0 ! G_Earth/Rho0 [L2 T-2 H-1 R-1 ~> m4 s-2 kg-1 or m7 s-2 kg-2].
142 real :: c2_scale ! A scaling factor for wave speeds to help control the growth of the determinant and
143 ! its derivative with lam between rows of the Thomas algorithm solver [L2 s2 T-2 m-2 ~> nondim].
144 ! The exact value should not matter for the final result if it is an even power of 2.
145 real :: tol_Hfrac ! Layers that together are smaller than this fraction of
146 ! the total water column can be merged for efficiency [nondim].
147 real :: min_h_frac ! tol_Hfrac divided by the total number of layers [nondim].
148 real :: tol_solve ! The fractional tolerance with which to solve for the wave speeds [nondim]
149 real :: tol_merge ! The fractional change in estimated wave speed that is allowed
150 ! when deciding to merge layers in the calculation [nondim]
151 real :: rescale ! A rescaling factor to control the magnitude of the determinant [nondim]
152 real :: I_rescale ! The reciprocal of the rescaling factor to control the magnitude of the determinant [nondim]
15348 integer :: kf(SZI_(G)) ! The number of active layers after filtering.
154 integer, parameter :: max_itt = 10
155 real :: lam_it(max_itt) ! The guess at the eignevalue with each iteration [T2 L-2 ~> s2 m-2]
156 real :: det_it(max_itt), ddet_it(max_itt) ! The determinant of the matrix and its derivative with lam
157 ! with each iteration. Because of all of the dynamic rescaling of the determinant
158 ! between rows, its units are not easily interpretable, but the ratio of det/ddet
159 ! always has units of [T2 L-2 ~> s2 m-2]
160 logical :: use_EOS ! If true, density or specific volume is calculated from T & S using an equation of state.
161 logical :: nonBous ! If true, do not make the Boussinesq approximation.
162 logical :: better_est ! If true, use an improved estimate of the first mode internal wave speed.
163 logical :: merge ! If true, merge the current layer with the one above.
164 integer :: kc ! The number of layers in the column after merging
165 integer :: i, j, k, k2, itt, is, ie, js, je, nz, halo
166 real :: hw ! The mean of the adjacent layer thicknesses [H ~> m or kg m-2]
167 real :: sum_hc ! The sum of the layer thicknesses [H ~> m or kg m-2]
168 real :: gp ! A limited local copy of gprime [L2 H-1 T-2 ~> m s-2 or m4 s-2 kg-1]
169 real :: N2min ! A minimum buoyancy frequency, including a slope rescaling factor [L2 H-2 T-2 ~> s-2 or m6 kg-2 s-2]
170 logical :: below_mono_N2_frac ! True if an interface is below the fractional depth where N2 should not increase.
171 logical :: below_mono_N2_depth ! True if an interface is below the absolute depth where N2 should not increase.
172 logical :: l_use_ebt_mode, calc_modal_structure
173 real :: l_mono_N2_column_fraction ! A local value of mono_N2_column_fraction [nondim]
174 real :: l_mono_N2_depth ! A local value of mono_N2_column_depth [H ~> m or kg m-2]
17548 real :: mode_struct(SZK_(GV)) ! The mode structure [nondim], but it is also temporarily
176 ! in units of [L2 T-2 ~> m2 s-2] after it is modified inside of tdma6.
177 real :: ms_min, ms_max ! The minimum and maximum mode structure values returned from tdma6 [L2 T-2 ~> m2 s-2]
178 real :: ms_sq ! The sum of the square of the values returned from tdma6 [L4 T-4 ~> m4 s-4]
179
18024 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke ; halo = 0
181
18224 if (.not. CS%initialized) call MOM_error(FATAL, "MOM_wave_speed / wave_speed: "// &
1830 "Module must be initialized before it is used.")
184
18524 if (present(halo_size)) then
1860 halo = halo_size
1870 is = G%isc - halo ; ie = G%iec + halo ; js = G%jsc - halo ; je = G%jec + halo
188 endif
189
19024 l_use_ebt_mode = CS%use_ebt_mode
19124 if (present(use_ebt_mode)) l_use_ebt_mode = use_ebt_mode
19224 l_mono_N2_column_fraction = CS%mono_N2_column_fraction
19324 if (present(mono_N2_column_fraction)) l_mono_N2_column_fraction = mono_N2_column_fraction
19424 l_mono_N2_depth = CS%mono_N2_depth
19524 if (present(mono_N2_depth)) l_mono_N2_depth = mono_N2_depth
19624 calc_modal_structure = l_use_ebt_mode
19724 if (present(modal_structure)) calc_modal_structure = .true.
19824 if (calc_modal_structure) then
1990 do k=1,nz ; do j=js,je ; do i=is,ie
2000 modal_structure(i,j,k) = 0.0
201 enddo ; enddo ; enddo
202 endif
203
20424 nonBous = .not.(GV%Boussinesq .or. GV%semi_Boussinesq)
20524 H_to_pres = GV%H_to_RZ * GV%g_Earth
206 ! Note that g_Rho0 = H_to_pres / GV%Rho0**2
20724 if (.not.nonBous) g_Rho0 = GV%g_Earth*GV%H_to_Z / GV%Rho0
20824 use_EOS = associated(tv%eqn_of_state)
209
21024 better_est = CS%better_cg1_est
211
21224 if (better_est) then
21324 tol_solve = CS%wave_speed_tol
21424 tol_Hfrac = 0.1*tol_solve ; tol_merge = tol_solve / real(nz)
215 else
2160 tol_solve = 0.001 ; tol_Hfrac = 0.0001 ; tol_merge = 0.001
217 endif
218
219 ! The rescaling below can control the growth of the determinant provided that
220 ! (tol_merge*cg1_min2/c2_scale > I_rescale). For default values, this suggests a stable lower
221 ! bound on min_speed of sqrt(nz/(tol_solve*rescale)) or 3e2/1024**2 = 2.9e-4 m/s for 90 layers.
222 ! The upper bound on the rate of increase in the determinant is g'H/c2_scale < rescale or in the
223 ! worst possible oceanic case of g'H < 0.5*10m/s2*1e4m = 5.e4 m2/s2 < 1024**2*c2_scale, suggesting
224 ! that c2_scale can safely be set to 1/(16*1024**2), which would decrease the stable floor on
225 ! min_speed to ~6.9e-8 m/s for 90 layers or 2.33e-7 m/s for 1000 layers.
22624 cg1_min2 = CS%min_speed2
22724 rescale = 1024.0**4 ; I_rescale = 1.0/rescale
22824 c2_scale = US%m_s_to_L_T**2 / 4096.0**2 ! Other powers of 2 give identical results.
229
23024 min_h_frac = tol_Hfrac / real(nz)
231 !$OMP parallel do default(private) shared(is,ie,js,je,nz,h,G,GV,US,tv,use_EOS,nonBous, &
232 !$OMP CS,min_h_frac,calc_modal_structure,l_use_ebt_mode, &
233 !$OMP modal_structure,l_mono_N2_column_fraction,l_mono_N2_depth, &
234 !$OMP H_to_pres,cg1,g_Rho0,rescale,I_rescale,cg1_min2, &
235 !$OMP better_est,tol_solve,tol_merge,c2_scale)
2361464 do j=js,je
237 ! First merge very thin layers with the one above (or below if they are
238 ! at the top). This also transposes the row order so that columns can
239 ! be worked upon one at a time.
240174240 do i=is,ie ; htot(i) = 0.0 ; enddo
24113069440 do k=1,nz ; do i=is,ie ; htot(i) = htot(i) + h(i,j,k) ; enddo ; enddo
242
243174240 do i=is,ie
244172800 hmin(i) = htot(i)*min_h_frac ; kf(i) = 1 ; H_here(i) = 0.0
245174240 HxT_here(i) = 0.0 ; HxS_here(i) = 0.0 ; HxR_here(i) = 0.0
246 enddo
2471440 if (use_EOS) then
24813069440 do k=1,nz ; do i=is,ie
24913068000 if ((H_here(i) > hmin(i)) .and. (h(i,j,k) > hmin(i))) then
25010708848 Hf(kf(i),i) = H_here(i)
25110708848 Tf(kf(i),i) = HxT_here(i) / H_here(i)
25210708848 Sf(kf(i),i) = HxS_here(i) / H_here(i)
25310708848 kf(i) = kf(i) + 1
254
255 ! Start a new layer
25610708848 H_here(i) = h(i,j,k)
25710708848 HxT_here(i) = h(i,j,k) * tv%T(i,j,k)
25810708848 HxS_here(i) = h(i,j,k) * tv%S(i,j,k)
259 else
2602251152 H_here(i) = H_here(i) + h(i,j,k)
2612251152 HxT_here(i) = HxT_here(i) + h(i,j,k) * tv%T(i,j,k)
2622251152 HxS_here(i) = HxS_here(i) + h(i,j,k) * tv%S(i,j,k)
263 endif
264 enddo ; enddo
265174240 do i=is,ie ; if (H_here(i) > 0.0) then
266172800 Hf(kf(i),i) = H_here(i)
267172800 Tf(kf(i),i) = HxT_here(i) / H_here(i)
268172800 Sf(kf(i),i) = HxS_here(i) / H_here(i)
269 endif ; enddo
270 else ! .not. (use_EOS)
2710 do k=1,nz ; do i=is,ie
2720 if ((H_here(i) > hmin(i)) .and. (h(i,j,k) > hmin(i))) then
2730 Hf(kf(i),i) = H_here(i) ; Rf(kf(i),i) = HxR_here(i) / H_here(i)
2740 kf(i) = kf(i) + 1
275
276 ! Start a new layer
2770 H_here(i) = h(i,j,k)
2780 HxR_here(i) = h(i,j,k)*GV%Rlay(k)
279 else
2800 H_here(i) = H_here(i) + h(i,j,k)
2810 HxR_here(i) = HxR_here(i) + h(i,j,k)*GV%Rlay(k)
282 endif
283 enddo ; enddo
2840 do i=is,ie ; if (H_here(i) > 0.0) then
2850 Hf(kf(i),i) = H_here(i) ; Rf(kf(i),i) = HxR_here(i) / H_here(i)
286 endif ; enddo
287 endif
288
289 ! From this point, we can work on individual columns without causing memory to have page faults.
290174264 do i=is,ie ; if (G%mask2dT(i,j) > 0.0) then
291120336 if (use_EOS) then
292120336 pres(1) = 0.0 ; H_top(1) = 0.0
2936946848 do K=2,kf(i)
2946826512 pres(K) = pres(K-1) + H_to_pres*Hf(k-1,i)
2956826512 T_int(K) = 0.5*(Tf(k,i)+Tf(k-1,i))
2966826512 S_int(K) = 0.5*(Sf(k,i)+Sf(k-1,i))
2976946848 H_top(K) = H_top(K-1) + Hf(k-1,i)
298 enddo
299120336 if (nonBous) then
300 call calculate_specific_vol_derivs(T_int, S_int, pres, dSpV_dT, dSpV_dS, &
3010 tv%eqn_of_state, (/2,kf(i)/) )
302 else
303 call calculate_density_derivs(T_int, S_int, pres, drho_dT, drho_dS, &
304361008 tv%eqn_of_state, (/2,kf(i)/) )
305 endif
306
307 ! Sum the reduced gravities to find out how small a density difference is negligibly small.
308120336 drxh_sum = 0.0 ; dSpVxh_sum = 0.0
309120336 if (better_est) then
310 ! This is an estimate that is correct for the non-EBT mode for 2 or 3 layers, or for
311 ! clusters of massless layers at interfaces that can be grouped into 2 or 3 layers.
312 ! For a uniform stratification and a huge number of layers uniformly distributed in
313 ! density, this estimate is too large (as is desired) by a factor of pi^2/6 ~= 1.64.
314120336 if (H_top(kf(i)) > 0.0) then
315120336 I_Htot = 1.0 / (H_top(kf(i)) + Hf(kf(i),i)) ! = 1.0 / (H_top(K) + H_bot(K)) for all K.
316120336 H_bot(kf(i)+1) = 0.0
317120336 if (nonBous) then
3180 do K=kf(i),2,-1
3190 H_bot(K) = H_bot(K+1) + Hf(k,i)
320 dSpVxh_sum = dSpVxh_sum + ((H_top(K) * H_bot(K)) * I_Htot) * &
3210 min(0.0, dSpV_dT(K)*(Tf(k,i)-Tf(k-1,i)) + dSpV_dS(K)*(Sf(k,i)-Sf(k-1,i)))
322 enddo
323 else
3246946848 do K=kf(i),2,-1
3256826512 H_bot(K) = H_bot(K+1) + Hf(k,i)
326 drxh_sum = drxh_sum + ((H_top(K) * H_bot(K)) * I_Htot) * &
3276946848 max(0.0, drho_dT(K)*(Tf(k,i)-Tf(k-1,i)) + drho_dS(K)*(Sf(k,i)-Sf(k-1,i)))
328 enddo
329 endif
330 endif
331 else
332 ! This estimate is problematic in that it goes like 1/nz for a large number of layers,
333 ! but it is an overestimate (as desired) for a small number of layers, by at a factor
334 ! of (H1+H2)**2/(H1*H2) >= 4 for two thick layers.
3350 if (nonBous) then
3360 do K=2,kf(i)
337 dSpVxh_sum = dSpVxh_sum + 0.5*(Hf(k-1,i)+Hf(k,i)) * &
3380 min(0.0, dSpV_dT(K)*(Tf(k,i)-Tf(k-1,i)) + dSpV_dS(K)*(Sf(k,i)-Sf(k-1,i)))
339 enddo
340 else
3410 do K=2,kf(i)
342 drxh_sum = drxh_sum + 0.5*(Hf(k-1,i)+Hf(k,i)) * &
3430 max(0.0, drho_dT(K)*(Tf(k,i)-Tf(k-1,i)) + drho_dS(K)*(Sf(k,i)-Sf(k-1,i)))
344 enddo
345 endif
346 endif
347 else ! .not. (use_EOS)
3480 drxh_sum = 0.0 ; dSpVxh_sum = 0.0
3490 if (better_est) then
3500 H_top(1) = 0.0
3510 do K=2,kf(i) ; H_top(K) = H_top(K-1) + Hf(k-1,i) ; enddo
3520 if (H_top(kf(i)) > 0.0) then
3530 I_Htot = 1.0 / (H_top(kf(i)) + Hf(kf(i),i)) ! = 1.0 / (H_top(K) + H_bot(K)) for all K.
3540 H_bot(kf(i)+1) = 0.0
3550 if (nonBous) then
3560 do K=kf(i),2,-1
3570 H_bot(K) = H_bot(K+1) + Hf(k,i)
358 dSpVxh_sum = dSpVxh_sum + ((H_top(K) * H_bot(K)) * I_Htot) * &
3590 min(0.0, (Rf(k-1,i)-Rf(k,i)) / (Rf(k,i)*Rf(k-1,i)))
360 enddo
361 else
3620 do K=kf(i),2,-1
3630 H_bot(K) = H_bot(K+1) + Hf(k,i)
3640 drxh_sum = drxh_sum + ((H_top(K) * H_bot(K)) * I_Htot) * max(0.0,Rf(k,i)-Rf(k-1,i))
365 enddo
366 endif
367 endif
368 else
3690 if (nonBous) then
3700 do K=2,kf(i)
371 dSpVxh_sum = dSpVxh_sum + 0.5*(Hf(k-1,i)+Hf(k,i)) * &
3720 min(0.0, (Rf(k-1,i)-Rf(k,i)) / (Rf(k,i)*Rf(k-1,i)))
373 enddo
374 else
3750 do K=2,kf(i)
3760 drxh_sum = drxh_sum + 0.5*(Hf(k-1,i)+Hf(k,i)) * max(0.0,Rf(k,i)-Rf(k-1,i))
377 enddo
378 endif
379 endif
380 endif ! use_EOS
381
382120336 if (nonBous) then
383 ! Note that dSpVxh_sum is negative for stable stratification.
3840 cg1_est = H_to_pres * abs(dSpVxh_sum)
385 else
386120336 cg1_est = g_Rho0 * drxh_sum
387 endif
388
389 ! Find gprime across each internal interface, taking care of convective instabilities by
390 ! merging layers. If the estimated wave speed is too small, simply return zero.
391120336 if (cg1_est <= cg1_min2) then
3921132 cg1(i,j) = 0.0
3931132 if (present(modal_structure)) modal_structure(i,j,:) = 0.
394 else
395 ! Merge layers to eliminate convective instabilities or exceedingly
396 ! small reduced gravities. Merging layers reduces the estimated wave speed by
397 ! (rho(2)-rho(1))*h(1)*h(2) / H_tot.
398119204 if (use_EOS) then
399119204 kc = 1
400119204 Hc(1) = Hf(1,i) ; Tc(1) = Tf(1,i) ; Sc(1) = Sf(1,i)
4016861948 do k=2,kf(i)
4026742744 if (better_est .and. nonBous) then
403 merge = ((dSpV_dT(K)*(Tc(kc)-Tf(k,i)) + dSpV_dS(K)*(Sc(kc)-Sf(k,i))) * &
4040 ((Hc(kc) * Hf(k,i))*I_Htot) < abs(2.0 * tol_merge * dSpVxh_sum))
4056742744 elseif (better_est) then
406 merge = ((drho_dT(K)*(Tf(k,i)-Tc(kc)) + drho_dS(K)*(Sf(k,i)-Sc(kc))) * &
4076742744 ((Hc(kc) * Hf(k,i))*I_Htot) < 2.0 * tol_merge*drxh_sum)
4080 elseif (nonBous) then
409 merge = ((dSpV_dT(K)*(Tc(kc)-Tf(k,i)) + dSpV_dS(K)*(Sc(kc)-Sf(k,i))) * &
4100 (Hc(kc) + Hf(k,i)) < abs(2.0 * tol_merge * dSpVxh_sum))
411 else
412 merge = ((drho_dT(K)*(Tf(k,i)-Tc(kc)) + drho_dS(K)*(Sf(k,i)-Sc(kc))) * &
4130 (Hc(kc) + Hf(k,i)) < 2.0 * tol_merge*drxh_sum)
414 endif
4156861948 if (merge) then
416 ! Merge this layer with the one above and backtrack.
4173497750 I_Hnew = 1.0 / (Hc(kc) + Hf(k,i))
4183497750 Tc(kc) = (Hc(kc)*Tc(kc) + Hf(k,i)*Tf(k,i)) * I_Hnew
4193497750 Sc(kc) = (Hc(kc)*Sc(kc) + Hf(k,i)*Sf(k,i)) * I_Hnew
4203497750 Hc(kc) = (Hc(kc) + Hf(k,i))
421 ! Backtrack to remove any convective instabilities above... Note
422 ! that the tolerance is a factor of two larger, to avoid limit how
423 ! far back we go.
4243497750 do K2=kc,2,-1
4251679634 if (better_est .and. nonBous) then
426 merge = ( (dSpV_dT(K2)*(Tc(k2-1)-Tc(k2)) + dSpV_dS(K2)*(Sc(k2-1)-Sc(k2))) * &
4270 ((Hc(k2) * Hc(k2-1))*I_Htot) < abs(tol_merge * dSpVxh_sum) )
4281679634 elseif (better_est) then
429 merge = ((drho_dT(K2)*(Tc(k2)-Tc(k2-1)) + drho_dS(K2)*(Sc(k2)-Sc(k2-1))) * &
4301679634 ((Hc(k2) * Hc(k2-1))*I_Htot) < tol_merge*drxh_sum)
4310 elseif (nonBous) then
432 merge = ( (dSpV_dT(K2)*(Tc(k2-1)-Tc(k2)) + dSpV_dS(K2)*(Sc(k2-1)-Sc(k2))) * &
4330 (Hc(k2) + Hc(k2-1)) < abs(tol_merge * dSpVxh_sum) )
434 else
435 merge = ((drho_dT(K2)*(Tc(k2)-Tc(k2-1)) + drho_dS(K2)*(Sc(k2)-Sc(k2-1))) * &
4360 (Hc(k2) + Hc(k2-1)) < tol_merge*drxh_sum)
437 endif
4383497750 if (merge) then
439 ! Merge the two bottommost layers. At this point kc = k2.
4400 I_Hnew = 1.0 / (Hc(kc) + Hc(kc-1))
4410 Tc(kc-1) = (Hc(kc)*Tc(kc) + Hc(kc-1)*Tc(kc-1)) * I_Hnew
4420 Sc(kc-1) = (Hc(kc)*Sc(kc) + Hc(kc-1)*Sc(kc-1)) * I_Hnew
4430 Hc(kc-1) = (Hc(kc) + Hc(kc-1))
4440 kc = kc - 1
4451679634 else ; exit ; endif
446 enddo
447 else
448 ! Add a new layer to the column.
4493244994 kc = kc + 1
4503244994 if (nonBous) then
4510 dSpV_dS(Kc) = dSpV_dS(K) ; dSpV_dT(Kc) = dSpV_dT(K)
452 else
4533244994 drho_dS(Kc) = drho_dS(K) ; drho_dT(Kc) = drho_dT(K)
454 endif
4553244994 Tc(kc) = Tf(k,i) ; Sc(kc) = Sf(k,i) ; Hc(kc) = Hf(k,i)
456 endif
457 enddo
458 ! At this point there are kc layers and the gprimes should be positive.
459119204 if (nonBous) then
4600 do K=2,kc
4610 gprime(K) = H_to_pres * (dSpV_dT(K)*(Tc(k-1)-Tc(k)) + dSpV_dS(K)*(Sc(k-1)-Sc(k)))
462 enddo
463 else
4643364198 do K=2,kc
4653364198 gprime(K) = g_Rho0 * (drho_dT(K)*(Tc(k)-Tc(k-1)) + drho_dS(K)*(Sc(k)-Sc(k-1)))
466 enddo
467 endif
468 else ! .not. (use_EOS)
469 ! Do the same with density directly...
4700 kc = 1
4710 Hc(1) = Hf(1,i) ; Rc(1) = Rf(1,i)
4720 do k=2,kf(i)
4730 if (nonBous .and. better_est) then
474 merge = ((Rf(k,i) - Rc(kc)) * ((Hc(kc) * Hf(k,i))*I_Htot) < &
4750 (Rc(kc)*Rf(k,i)) * abs(2.0 * tol_merge * dSpVxh_sum))
4760 elseif (nonBous) then
477 merge = ((Rf(k,i) - Rc(kc)) * (Hc(kc) + Hf(k,i)) < &
4780 (Rc(kc)*Rf(k,i)) * abs(2.0 * tol_merge * dSpVxh_sum))
4790 elseif (better_est) then
4800 merge = ((Rf(k,i) - Rc(kc)) * ((Hc(kc) * Hf(k,i))*I_Htot) < 2.0*tol_merge*drxh_sum)
481 else
4820 merge = ((Rf(k,i) - Rc(kc)) * (Hc(kc) + Hf(k,i)) < 2.0*tol_merge*drxh_sum)
483 endif
4840 if (merge) then
485 ! Merge this layer with the one above and backtrack.
4860 Rc(kc) = (Hc(kc)*Rc(kc) + Hf(k,i)*Rf(k,i)) / (Hc(kc) + Hf(k,i))
4870 Hc(kc) = (Hc(kc) + Hf(k,i))
488 ! Backtrack to remove any convective instabilities above... Note
489 ! that the tolerance is a factor of two larger, to avoid limit how
490 ! far back we go.
4910 do k2=kc,2,-1
4920 if (nonBous .and. better_est) then
493 merge = ((Rc(k2) - Rc(k2-1)) * ((Hc(kc) * Hf(k,i))*I_Htot) < &
4940 (Rc(k2-1)*Rc(k2)) * abs(2.0 * tol_merge * dSpVxh_sum))
4950 elseif (nonBous) then
496 merge = ((Rc(k2) - Rc(k2-1)) * (Hc(kc) + Hf(k,i)) < &
4970 (Rc(k2-1)*Rc(k2)) * abs(2.0 * tol_merge * dSpVxh_sum))
4980 elseif (better_est) then
4990 merge = ((Rc(k2)-Rc(k2-1)) * ((Hc(k2) * Hc(k2-1))*I_Htot) < tol_merge*drxh_sum)
500 else
5010 merge = ((Rc(k2)-Rc(k2-1)) * (Hc(k2)+Hc(k2-1)) < tol_merge*drxh_sum)
502 endif
5030 if (merge) then
504 ! Merge the two bottommost layers. At this point kc = k2.
5050 Rc(kc-1) = (Hc(kc)*Rc(kc) + Hc(kc-1)*Rc(kc-1)) / (Hc(kc) + Hc(kc-1))
5060 Hc(kc-1) = (Hc(kc) + Hc(kc-1))
5070 kc = kc - 1
5080 else ; exit ; endif
509 enddo
510 else
511 ! Add a new layer to the column.
5120 kc = kc + 1
5130 Rc(kc) = Rf(k,i) ; Hc(kc) = Hf(k,i)
514 endif
515 enddo
516 ! At this point there are kc layers and the gprimes should be positive.
5170 if (nonBous) then
5180 do K=2,kc
5190 gprime(K) = H_to_pres * (Rc(k) - Rc(k-1)) / (Rc(k) * Rc(k-1))
520 enddo
521 else
5220 do K=2,kc
5230 gprime(K) = g_Rho0 * (Rc(k)-Rc(k-1))
524 enddo
525 endif
526 endif ! use_EOS
527
528 ! Sum the contributions from all of the interfaces to give an over-estimate
529 ! of the first-mode wave speed. Also populate Igl and Igu which are the
530 ! non-leading diagonals of the tridiagonal matrix.
531119204 if (kc >= 2) then
532118621 speed2_tot = 0.0
533118621 if (better_est) then
534118621 H_top(1) = 0.0 ; H_bot(kc+1) = 0.0
5353482236 do K=2,kc+1 ; H_top(K) = H_top(K-1) + Hc(k-1) ; enddo
5363363615 do K=kc,2,-1 ; H_bot(K) = H_bot(K+1) + Hc(k) ; enddo
537118621 I_Htot = 0.0 ; if (H_top(kc+1) > 0.0) I_Htot = 1.0 / H_top(kc+1)
538 endif
539
540118621 if (l_use_ebt_mode) then
5410 Igu(1) = 0. ! Neumann condition for pressure modes
5420 sum_hc = Hc(1)
5430 N2min = gprime(2)/Hc(1)
544
5450 below_mono_N2_frac = .false.
5460 below_mono_N2_depth = .false.
5470 do k=2,kc
5480 hw = 0.5*(Hc(k-1)+Hc(k))
5490 gp = gprime(K)
550
5510 if (l_mono_N2_column_fraction>0. .or. l_mono_N2_depth>=0.) then
552 ! Determine whether N2 estimates should not be allowed to increase with depth.
5530 if (l_mono_N2_column_fraction>0.) then
5540 if (GV%Boussinesq .or. GV%semi_Boussinesq) then
555 below_mono_N2_frac = &
556 (max(G%meanSL(i,j) + G%bathyT(i,j), 0.0) - GV%H_to_Z * sum_hc < &
5570 l_mono_N2_column_fraction * max(G%meanSL(i,j) + G%bathyT(i,j), 0.0))
558 else
5590 below_mono_N2_frac = (htot(i) - sum_hc < l_mono_N2_column_fraction*htot(i))
560 endif
561 endif
5620 if (l_mono_N2_depth >= 0.) below_mono_N2_depth = (sum_hc > l_mono_N2_depth)
563
5640 if ( (gp > N2min*hw) .and. (below_mono_N2_frac .or. below_mono_N2_depth) ) then
565 ! Filters out regions where N2 increases with depth, but only in a lower fraction
566 ! of the water column or below a certain depth.
5670 gp = N2min * hw
568 else
5690 N2min = gp / hw
570 endif
571 endif
572
5730 Igu(k) = 1.0/(gp*Hc(k))
5740 Igl(k-1) = 1.0/(gp*Hc(k-1))
5750 sum_hc = sum_hc + Hc(k)
576
5770 if (better_est) then
578 ! Estimate that the ebt_mode is sqrt(2) times the speed of the flat bottom modes.
5790 speed2_tot = speed2_tot + 2.0 * gprime(K)*((H_top(K) * H_bot(K)) * I_Htot)
580 else ! The ebt_mode wave should be faster than the flat-bottom mode, so 0.707 should be > 1?
5810 speed2_tot = speed2_tot + gprime(K)*(Hc(k-1)+Hc(k))*0.707
582 endif
583 enddo
584 !Igl(kc) = 0. ! Neumann condition for pressure modes
5850 Igl(kc) = 2.*Igu(kc) ! Dirichlet condition for pressure modes
586 else ! .not. l_use_ebt_mode
5873363615 do K=2,kc
5883244994 Igl(K) = 1.0/(gprime(K)*Hc(k)) ; Igu(K) = 1.0/(gprime(K)*Hc(k-1))
5893363615 if (better_est) then
5903244994 speed2_tot = speed2_tot + gprime(K)*((H_top(K) * H_bot(K)) * I_Htot)
591 else
5920 speed2_tot = speed2_tot + gprime(K)*(Hc(k-1)+Hc(k))
593 endif
594 enddo
595 endif
596
597118621 if (calc_modal_structure) then
5980 mode_struct(:) = 0.
5990 mode_struct(1:kc) = 1. ! Uniform flow, first guess
600 endif
601
602 ! Under estimate the first eigenvalue (overestimate the speed) to start with.
603118621 if (calc_modal_structure) then
6040 lam0 = 0.5 / speed2_tot ; lam = lam0
605 else
606118621 lam0 = 1.0 / speed2_tot ; lam = lam0
607 endif
608 ! Find the determinant and its derivative with lam.
609470070 do itt=1,max_itt
610470070 lam_it(itt) = lam
611470070 if (l_use_ebt_mode) then
612 ! This initialization of det,ddet imply Neumann boundary conditions for horizontal
613 ! velocity or pressure modes, so that first 3 rows of the matrix are
614 ! / b(1)-lam igl(1) 0 0 0 ... \
615 ! | igu(2) b(2)-lam igl(2) 0 0 ... |
616 ! | 0 igu(3) b(3)-lam igl(3) 0 ... |
617 ! The last two rows of the pressure equation matrix are
618 ! | ... 0 igu(kc-1) b(kc-1)-lam igl(kc-1) |
619 ! \ ... 0 0 igu(kc) b(kc)-lam /
6200 call tridiag_det(Igu, Igl, 1, kc, lam, det, ddet, row_scale=c2_scale)
621 else
622 ! This initialization of det,ddet imply Dirichlet boundary conditions for vertical
623 ! velocity modes, so that first 3 rows of the matrix are
624 ! / b(2)-lam igl(2) 0 0 0 ... |
625 ! | igu(3) b(3)-lam igl(3) 0 0 ... |
626 ! | 0 igu(4) b(4)-lam igl(4) 0 ... |
627 ! The last three rows of the w equation matrix are
628 ! | ... 0 igu(kc-2) b(kc-2)-lam igl(kc-2) 0 |
629 ! | ... 0 0 igu(kc-1) b(kc-1)-lam igl(kc-1) |
630 ! \ ... 0 0 0 igu(kc) b(kc)-lam /
631470070 call tridiag_det(Igu, Igl, 2, kc, lam, det, ddet, row_scale=c2_scale)
632 endif
633 ! Use Newton's method iteration to find a new estimate of lam.
634470070 det_it(itt) = det ; ddet_it(itt) = ddet
635
636470070 if ((ddet >= 0.0) .or. (-det > -0.5*lam*ddet)) then
637 ! lam was not an under-estimate, as intended, so Newton's method
638 ! may not be reliable; lam must be reduced, but not by more
639 ! than half.
6400 lam = 0.5 * lam
6410 dlam = -lam
642 else ! Newton's method is OK.
643470070 dlam = - det / ddet
644470070 lam = lam + dlam
645 endif
646
647470070 if (calc_modal_structure) then
6480 call tdma6(kc, Igu, Igl, lam, mode_struct)
649 ! Note that tdma6 changes the units of mode_struct to [L2 T-2 ~> m2 s-2]
6500 ms_min = mode_struct(1)
6510 ms_max = mode_struct(1)
6520 ms_sq = mode_struct(1)**2
6530 do k = 2,kc
6540 ms_min = min(ms_min, mode_struct(k))
6550 ms_max = max(ms_max, mode_struct(k))
6560 ms_sq = ms_sq + mode_struct(k)**2
657 enddo
6580 if (ms_min<0. .and. ms_max>0.) then ! Any zero crossings => lam is too high
6590 lam = 0.5 * ( lam - dlam )
6600 dlam = -lam
6610 mode_struct(1:kc) = abs(mode_struct(1:kc)) / sqrt( ms_sq )
662 else
6630 mode_struct(1:kc) = mode_struct(1:kc) / sqrt( ms_sq )
664 endif
665 ! After the nondimensionalization above, mode_struct is once again [nondim]
666 endif
667
668470070 if (abs(dlam) < tol_solve*lam) exit
669 enddo
670
671118621 cg1(i,j) = 0.0
672118621 if (lam > 0.0) cg1(i,j) = 1.0 / sqrt(lam)
673
674118621 if (present(modal_structure)) then
6750 if (mode_struct(1)/=0.) then ! Normalize
6760 mode_struct(1:kc) = mode_struct(1:kc) / mode_struct(1)
677 else
6780 mode_struct(1:kc)=0.
679 endif
680
6810 if (CS%remap_answer_date < 20190101) then
682 call remapping_core_h(CS%remap_2018_CS, kc, Hc(:), mode_struct, &
6830 nz, h(i,j,:), modal_structure(i,j,:))
684 else
685 call remapping_core_h(CS%remap_CS, kc, Hc(:), mode_struct, &
6860 nz, h(i,j,:), modal_structure(i,j,:))
687 endif
688 endif
689 else
690583 cg1(i,j) = 0.0
691583 if (present(modal_structure)) modal_structure(i,j,:) = 0.
692 endif
693 endif ! cg1 /= 0.0
694 else
69552464 cg1(i,j) = 0.0 ! This is a land point.
69652464 if (present(modal_structure)) modal_structure(i,j,:) = 0.
697 endif ; enddo ! i-loop
698 enddo ! j-loop
699
70024end subroutine wave_speed
701
702!> Solve a non-symmetric tridiagonal problem with the sum of the upper and lower diagonals minus a
703!! scalar contribution as the leading diagonal.
704!! This uses the Thomas algorithm rather than the Hallberg algorithm since the matrix is not symmetric.
7050subroutine tdma6(n, a, c, lam, y)
706 integer, intent(in) :: n !< Number of rows of matrix
707 real, dimension(:), intent(in) :: a !< Lower diagonal [T2 L-2 ~> s2 m-2]
708 real, dimension(:), intent(in) :: c !< Upper diagonal [T2 L-2 ~> s2 m-2]
709 real, intent(in) :: lam !< Scalar subtracted from leading diagonal [T2 L-2 ~> s2 m-2]
710 real, dimension(:), intent(inout) :: y !< RHS on entry [A ~> a], result on exit [A L2 T-2 ~> a m2 s-2]
711
712 ! Local variables
713 real :: lambda ! A temporary variable in [T2 L-2 ~> s2 m-2]
7140 real :: beta(n) ! A temporary variable in [T2 L-2 ~> s2 m-2]
7150 real :: I_beta(n) ! A temporary variable in [L2 T-2 ~> m2 s-2]
7160 real :: yy(n) ! A temporary variable with the same units as y on entry [A ~> a]
717 integer :: k, m
718
7190 lambda = lam
7200 beta(1) = (a(1)+c(1)) - lambda
7210 if (beta(1)==0.) then ! lam was chosen too perfectly
722 ! Change lambda and redo this first row
7230 lambda = (1. + 1.e-5) * lambda
7240 beta(1) = (a(1)+c(1)) - lambda
725 endif
7260 I_beta(1) = 1. / beta(1)
7270 yy(1) = y(1)
7280 do k = 2, n
7290 beta(k) = ( (a(k)+c(k)) - lambda ) - a(k) * c(k-1) * I_beta(k-1)
730 ! Perhaps the following 0 needs to become a tolerance to handle underflow?
7310 if (beta(k)==0.) then ! lam was chosen too perfectly
732 ! Change lambda and redo everything up to row k
7330 lambda = (1. + 1.e-5) * lambda
7340 I_beta(1) = 1. / ( (a(1)+c(1)) - lambda )
7350 do m = 2, k
7360 I_beta(m) = 1. / ( ( (a(m)+c(m)) - lambda ) - a(m) * c(m-1) * I_beta(m-1) )
7370 yy(m) = y(m) + a(m) * yy(m-1) * I_beta(m-1)
738 enddo
739 else
7400 I_beta(k) = 1. / beta(k)
741 endif
7420 yy(k) = y(k) + a(k) * yy(k-1) * I_beta(k-1)
743 enddo
744 ! The units of y change by a factor of [L2 T-2 ~> m2 s-2] in the following lines.
7450 y(n) = yy(n) * I_beta(n)
7460 do k = n-1, 1, -1
7470 y(k) = ( yy(k) + c(k) * y(k+1) ) * I_beta(k)
748 enddo
749
7500end subroutine tdma6
751
752!> Calculates the wave speeds for the first few barolinic modes.
7530subroutine wave_speeds(h, tv, G, GV, US, nmodes, cn, CS, w_struct, u_struct, u_struct_max, u_struct_bot, Nb, int_w2, &
7540 int_U2, int_N2w2, halo_size)
755 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
756 type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure
757 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
758 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer thickness [H ~> m or kg m-2]
759 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamic variables
760 integer, intent(in) :: nmodes !< Number of modes
761 type(wave_speed_CS), intent(in) :: CS !< Wave speed control struct
762 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1,nmodes),intent(out) :: w_struct !< Wave vertical velocity profile [nondim]
763 real, dimension(SZI_(G),SZJ_(G),SZK_(GV),nmodes),intent(out) :: u_struct !< Wave horizontal velocity profile
764 !! [Z-1 ~> m-1]
765 real, dimension(SZI_(G),SZJ_(G),nmodes), intent(out) :: cn !< Waves speeds [L T-1 ~> m s-1]
766 real, dimension(SZI_(G),SZJ_(G),nmodes), intent(out) :: u_struct_max !< Maximum of wave horizontal velocity
767 !! profile [Z-1 ~> m-1]
768 real, dimension(SZI_(G),SZJ_(G),nmodes), intent(out) :: u_struct_bot !< Bottom value of wave horizontal
769 !! velocity profile [Z-1 ~> m-1]
770 real, dimension(SZI_(G),SZJ_(G)), intent(out) :: Nb !< Bottom value of buoyancy freqency
771 !! [T-1 ~> s-1]
772 real, dimension(SZI_(G),SZJ_(G),nmodes), intent(out) :: int_w2 !< depth-integrated vertical velocity
773 !! profile squared [H ~> m or kg m-2]
774 real, dimension(SZI_(G),SZJ_(G),nmodes), intent(out) :: int_U2 !< depth-integrated horizontal velocity
775 !! profile squared [H Z-2 ~> m-1 or kg m-4]
776 real, dimension(SZI_(G),SZJ_(G),nmodes), intent(out) :: int_N2w2 !< depth-integrated buoyancy frequency
777 !! times vertical velocity profile
778 !! squared [H T-2 ~> m s-2 or kg m-2 s-2]
779 integer, optional, intent(in) :: halo_size !< Width of halo within which to
780 !! calculate wave speeds
781
782 ! Local variables
783 real, dimension(SZK_(GV)+1) :: &
7840 dRho_dT, & ! Partial derivative of density with temperature [R C-1 ~> kg m-3 degC-1]
7850 dRho_dS, & ! Partial derivative of density with salinity [R S-1 ~> kg m-3 ppt-1]
7860 dSpV_dT, & ! Partial derivative of specific volume with temperature [R-1 C-1 ~> m3 kg-1 degC-1]
7870 dSpV_dS, & ! Partial derivative of specific volume with salinity [R-1 S-1 ~> m3 kg-1 ppt-1]
7880 pres, & ! Interface pressure [R L2 T-2 ~> Pa]
7890 T_int, & ! Temperature interpolated to interfaces [C ~> degC]
7900 S_int, & ! Salinity interpolated to interfaces [S ~> ppt]
7910 H_top, & ! The distance of each filtered interface from the ocean surface [H ~> m or kg m-2]
7920 H_bot, & ! The distance of each filtered interface from the bottom [H ~> m or kg m-2]
7930 gprime, & ! The reduced gravity across each interface [L2 H-1 T-2 ~> m s-2 or m4 kg-1 s-2].
7940 N2 ! The buoyancy freqency squared [T-2 ~> s-2]
795 real, dimension(SZK_(GV),SZI_(G)) :: &
7960 Hf, & ! Layer thicknesses after very thin layers are combined [H ~> m or kg m-2]
7970 dzf, & ! Layer vertical extents after very thin layers are combined [Z ~> m]
7980 Tf, & ! Layer temperatures after very thin layers are combined [C ~> degC]
7990 Sf, & ! Layer salinities after very thin layers are combined [S ~> ppt]
8000 Rf ! Layer densities after very thin layers are combined [R ~> kg m-3]
801 real, dimension(SZI_(G),SZK_(GV)) :: &
8020 dz_2d ! Height change across layers [Z ~> m]
803 real, dimension(SZK_(GV)) :: &
8040 Igl, Igu, & ! The inverse of the reduced gravity across an interface times
805 ! the thickness of the layer below (Igl) or above (Igu) it, in [T2 L-2 ~> s2 m-2].
8060 Hc, & ! A column of layer thicknesses after convective instabilities are removed [H ~> m or kg m-2]
8070 dzc, & ! A column of layer vertical extents after convective instabilities are removed [Z ~> m]
8080 Tc, & ! A column of layer temperatures after convective instabilities are removed [C ~> degC]
8090 Sc, & ! A column of layer salinities after convective instabilities are removed [S ~> ppt]
8100 Rc ! A column of layer densities after convective instabilities are removed [R ~> kg m-3]
811 real :: I_Htot ! The inverse of the total filtered thicknesses [H-1 ~> m-1 or m2 kg-1]
812 real :: c2_scale ! A scaling factor for wave speeds to help control the growth of the determinant and its
813 ! derivative with lam between rows of the Thomas algorithm solver [L2 s2 T-2 m-2 ~> nondim].
814 ! The exact value should not matter for the final result if it is an even power of 2.
815 real :: det, ddet ! Determinant of the eigen system and its derivative with lam. Because the
816 ! units of the eigenvalue change with the number of layers and because of the
817 ! dynamic rescaling that is used to keep det in a numerically representable range,
818 ! the units of of det are hard to interpret, but det/ddet is always in units
819 ! of [T2 L-2 ~> s2 m-2]
820 real :: lam_1 ! approximate mode-1 eigenvalue [T2 L-2 ~> s2 m-2]
821 real :: lam_n ! approximate mode-n eigenvalue [T2 L-2 ~> s2 m-2]
822 real :: dlam ! The change in estimates of the eigenvalue [T2 L-2 ~> s2 m-2]
823 real :: lamMin ! minimum lam value for root searching range [T2 L-2 ~> s2 m-2]
824 real :: lamMax ! maximum lam value for root searching range [T2 L-2 ~> s2 m-2]
825 real :: lamInc ! width of moving window for root searching [T2 L-2 ~> s2 m-2]
826 real :: det_l, ddet_l ! determinant of the eigensystem and its derivative with lam at the lower
827 ! end of the range of values bracketing a particular root, in dynamically
828 ! rescaled units that may differ from the other det variables, but such
829 ! that the units of det_l/ddet_l are [T2 L-2 ~> s2 m-2]
830 real :: det_r, ddet_r ! determinant and its derivative with lam at the lower end of the
831 ! bracket in arbitrarily rescaled units, but such that the units of
832 ! det_r/ddet_r are [T2 L-2 ~> s2 m-2]
833 real :: det_sub, ddet_sub ! determinant and its derivative with lam at a subinterval endpoint that
834 ! is a candidate for a new bracket endpoint in arbitrarily rescaled units,
835 ! but such that the units of det_sub/ddet_sub are [T2 L-2 ~> s2 m-2]
836 real :: xl, xr ! lam guesses at left and right of window [T2 L-2 ~> s2 m-2]
837 real :: xl_sub ! lam guess at left of subinterval window [T2 L-2 ~> s2 m-2]
838 real, dimension(nmodes) :: &
8390 xbl, xbr ! lam guesses bracketing a zero-crossing (root) [T2 L-2 ~> s2 m-2]
840 integer :: numint ! number of widows (intervals) in root searching range
841 integer :: nrootsfound ! number of extra roots found (not including 1st root)
842 real :: H_to_pres ! A conversion factor from thicknesses to pressure [R L2 T-2 H-1 ~> Pa m-1 or Pa m2 kg-1]
843 real, dimension(SZI_(G)) :: &
8440 htot, hmin, & ! Thicknesses [H ~> m or kg m-2]
8450 H_here, & ! A layer thickness [H ~> m or kg m-2]
8460 dz_here, & ! A layer vertical extent [Z ~> m]
8470 HxT_here, & ! A layer integrated temperature [C H ~> degC m or degC kg m-2]
8480 HxS_here, & ! A layer integrated salinity [S H ~> ppt m or ppt kg m-2]
8490 HxR_here ! A layer integrated density [R H ~> kg m-2 or kg2 m-5]
850 real :: speed2_tot ! overestimate of the mode-1 speed squared [L2 T-2 ~> m2 s-2]
851 real :: speed2_min ! minimum mode speed (squared) to consider in root searching [L2 T-2 ~> m2 s-2]
852 real :: cg1_min2 ! A floor in the squared first mode speed below which 0 is returned [L2 T-2 ~> m2 s-2]
853 real :: cg1_est ! An initial estimate of the squared first mode speed [L2 T-2 ~> m2 s-2]
854 real, parameter :: reduct_factor = 0.5 ! A factor used in setting speed2_min [nondim]
855 real :: I_Hnew ! The inverse of a new layer thickness [H-1 ~> m-1 or m2 kg-1]
856 real :: drxh_sum ! The sum of density differences across interfaces times thicknesses [R H ~> kg m-2 or kg2 m-5]
857 real :: dSpVxh_sum ! The sum of specific volume differences across interfaces times
858 ! thicknesses [H R-1 ~> m4 kg-1 or m], negative for stable stratification.
859 real :: g_Rho0 ! G_Earth/Rho0 [L2 T-2 H-1 R-1 ~> m4 s-2 kg-1 or m7 s-2 kg-2].
860 real :: tol_Hfrac ! Layers that together are smaller than this fraction of
861 ! the total water column can be merged for efficiency [nondim].
862 real :: min_h_frac ! tol_Hfrac divided by the total number of layers [nondim].
863 real :: tol_solve ! The fractional tolerance with which to solve for the wave speeds [nondim].
864 real :: tol_merge ! The fractional change in estimated wave speed that is allowed
865 ! when deciding to merge layers in the calculation [nondim]
8660 integer :: kf(SZI_(G)) ! The number of active layers after filtering.
867 integer, parameter :: max_itt = 30
868 logical :: use_EOS ! If true, density or specific volume is calculated from T & S using the equation of state.
869 logical :: nonBous ! If true, do not make the Boussinesq approximation.
870 logical :: better_est ! If true, use an improved estimate of the first mode internal wave speed.
871 logical :: merge ! If true, merge the current layer with the one above.
872 integer :: nsub ! number of subintervals used for root finding
873 integer, parameter :: sub_it_max = 4
874 ! maximum number of times to subdivide interval
875 ! for root finding (# intervals = 2**sub_it_max)
876 logical :: sub_rootfound ! if true, subdivision has located root
877 integer :: kc ! The number of layers in the column after merging
878 integer :: sub, sub_it
879 integer :: i, j, k, k2, itt, is, ie, js, je, nz, iint, m, halo
8800 real, dimension(SZK_(GV)+1) :: modal_structure !< Normalized model structure [nondim]
8810 real, dimension(SZK_(GV)) :: modal_structure_fder !< Normalized model structure [Z-1 ~> m-1]
8820 real :: mode_struct(SZK_(GV)+1) ! The mode structure [nondim], but it is also temporarily
883 ! in units of [L2 T-2 ~> m2 s-2] after it is modified inside of tdma6.
8840 real :: mode_struct_fder(SZK_(GV)) ! The mode structure 1st derivative [Z-1 ~> m-1], but it is also temporarily
885 ! in units of [L2 Z-1 T-2 ~> m s-2] after it is modified inside of tdma6.
8860 real :: mode_struct_sq(SZK_(GV)+1) ! The square of mode structure [nondim]
8870 real :: mode_struct_fder_sq(SZK_(GV)) ! The square of mode structure 1st derivative [Z-2 ~> m-2]
888
889 real :: w2avg ! A total for renormalization [H L4 T-4 ~> m5 s-4 or kg m2 s-4]
890 real, parameter :: a_int = 0.5 ! Integral total for normalization [nondim]
891 real :: renorm ! Normalization factor [T2 L-2 ~> s2 m-2]
892
8930 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke ; halo = 0
894
8950 if (.not. CS%initialized) call MOM_error(FATAL, "MOM_wave_speed / wave_speeds: "// &
8960 "Module must be initialized before it is used.")
897
8980 if (present(halo_size)) then
8990 halo = halo_size
9000 is = G%isc - halo ; ie = G%iec + halo ; js = G%jsc - halo ; je = G%jec + halo
901 endif
902
9030 nonBous = .not.(GV%Boussinesq .or. GV%semi_Boussinesq)
9040 H_to_pres = GV%H_to_RZ * GV%g_Earth
9050 if (.not.nonBous) g_Rho0 = GV%g_Earth * GV%H_to_Z / GV%Rho0
9060 use_EOS = associated(tv%eqn_of_state)
907
9080 if (CS%c1_thresh < 0.0) &
909 call MOM_error(FATAL, "INTERNAL_WAVE_CG1_THRESH must be set to a non-negative "//&
9100 "value via wave_speed_init for wave_speeds to be used.")
9110 c2_scale = US%m_s_to_L_T**2 / 4096.0**2 ! Other powers of 2 give identical results.
912
9130 better_est = CS%better_cg1_est
9140 if (better_est) then
9150 tol_solve = CS%wave_speed_tol
9160 tol_Hfrac = 0.1*tol_solve ; tol_merge = tol_solve / real(nz)
917 else
9180 tol_solve = 0.001 ; tol_Hfrac = 0.0001 ; tol_merge = 0.001
919 endif
9200 cg1_min2 = CS%min_speed2
921
922 ! Zero out all local values. Values over land or for columns that are too weakly stratified
923 ! are not changed from this zero value.
9240 cn(:,:,:) = 0.0
9250 u_struct_max(:,:,:) = 0.0
9260 u_struct_bot(:,:,:) = 0.0
9270 Nb(:,:) = 0.0
9280 int_w2(:,:,:) = 0.0
9290 int_N2w2(:,:,:) = 0.0
9300 int_U2(:,:,:) = 0.0
9310 u_struct(:,:,:,:) = 0.0
9320 w_struct(:,:,:,:) = 0.0
933
9340 min_h_frac = tol_Hfrac / real(nz)
935 !$OMP parallel do default(private) shared(is,ie,js,je,nz,h,G,GV,US,CS,use_EOS,nonBous, &
936 !$OMP min_h_frac,H_to_pres,tv,cn,g_Rho0,nmodes,cg1_min2, &
937 !$OMP better_est,tol_solve,tol_merge,c2_scale)
9380 do j=js,je
939 ! First merge very thin layers with the one above (or below if they are
940 ! at the top). This also transposes the row order so that columns can
941 ! be worked upon one at a time.
9420 do i=is,ie ; htot(i) = 0.0 ; enddo
9430 do k=1,nz ; do i=is,ie ; htot(i) = htot(i) + h(i,j,k) ; enddo ; enddo
944
9450 call thickness_to_dz(h, tv, dz_2d, j, G, GV, halo_size=halo)
946
9470 do i=is,ie
9480 hmin(i) = htot(i)*min_h_frac ; kf(i) = 1 ; H_here(i) = 0.0 ; dz_here(i) = 0.0
9490 HxT_here(i) = 0.0 ; HxS_here(i) = 0.0 ; HxR_here(i) = 0.0
950 enddo
9510 if (use_EOS) then
9520 do k=1,nz ; do i=is,ie
9530 if ((H_here(i) > hmin(i)) .and. (h(i,j,k) > hmin(i))) then
9540 Hf(kf(i),i) = H_here(i)
9550 dzf(kf(i),i) = dz_here(i)
9560 Tf(kf(i),i) = HxT_here(i) / H_here(i)
9570 Sf(kf(i),i) = HxS_here(i) / H_here(i)
9580 kf(i) = kf(i) + 1
959
960 ! Start a new layer
9610 H_here(i) = h(i,j,k)
9620 dz_here(i) = dz_2d(i,k)
9630 HxT_here(i) = h(i,j,k)*tv%T(i,j,k)
9640 HxS_here(i) = h(i,j,k)*tv%S(i,j,k)
965 else
9660 H_here(i) = H_here(i) + h(i,j,k)
9670 dz_here(i) = dz_here(i) + dz_2d(i,k)
9680 HxT_here(i) = HxT_here(i) + h(i,j,k)*tv%T(i,j,k)
9690 HxS_here(i) = HxS_here(i) + h(i,j,k)*tv%S(i,j,k)
970 endif
971 enddo ; enddo
9720 do i=is,ie ; if (H_here(i) > 0.0) then
9730 Hf(kf(i),i) = H_here(i)
9740 dzf(kf(i),i) = dz_here(i)
9750 Tf(kf(i),i) = HxT_here(i) / H_here(i)
9760 Sf(kf(i),i) = HxS_here(i) / H_here(i)
977 endif ; enddo
978 else ! .not. (use_EOS)
9790 do k=1,nz ; do i=is,ie
9800 if ((H_here(i) > hmin(i)) .and. (h(i,j,k) > hmin(i))) then
9810 Hf(kf(i),i) = H_here(i) ; Rf(kf(i),i) = HxR_here(i) / H_here(i)
9820 dzf(kf(i),i) = dz_here(i)
9830 kf(i) = kf(i) + 1
984
985 ! Start a new layer
9860 H_here(i) = h(i,j,k)
9870 dz_here(i) = dz_2d(i,k)
9880 HxR_here(i) = h(i,j,k)*GV%Rlay(k)
989 else
9900 H_here(i) = H_here(i) + h(i,j,k)
9910 dz_here(i) = dz_here(i) + dz_2d(i,k)
9920 HxR_here(i) = HxR_here(i) + h(i,j,k)*GV%Rlay(k)
993 endif
994 enddo ; enddo
9950 do i=is,ie ; if (H_here(i) > 0.0) then
9960 Hf(kf(i),i) = H_here(i) ; Rf(kf(i),i) = HxR_here(i) / H_here(i)
9970 dzf(kf(i),i) = dz_here(i)
998 endif ; enddo
999 endif
1000
1001 ! From this point, we can work on individual columns without causing memory to have page faults.
10020 do i=is,ie
10030 if (G%mask2dT(i,j) > 0.0) then
10040 if (use_EOS) then
10050 pres(1) = 0.0 ; H_top(1) = 0.0
10060 do K=2,kf(i)
10070 pres(K) = pres(K-1) + H_to_pres*Hf(k-1,i)
10080 T_int(K) = 0.5*(Tf(k,i)+Tf(k-1,i))
10090 S_int(K) = 0.5*(Sf(k,i)+Sf(k-1,i))
10100 H_top(K) = H_top(K-1) + Hf(k-1,i)
1011 enddo
10120 if (nonBous) then
1013 call calculate_specific_vol_derivs(T_int, S_int, pres, dSpV_dT, dSpV_dS, &
10140 tv%eqn_of_state, (/2,kf(i)/) )
1015 else
1016 call calculate_density_derivs(T_int, S_int, pres, drho_dT, drho_dS, &
10170 tv%eqn_of_state, (/2,kf(i)/) )
1018 endif
1019
1020 ! Sum the reduced gravities to find out how small a density difference is negligibly small.
10210 drxh_sum = 0.0 ; dSpVxh_sum = 0.0
10220 if (better_est) then
1023 ! This is an estimate that is correct for the non-EBT mode for 2 or 3 layers, or for
1024 ! clusters of massless layers at interfaces that can be grouped into 2 or 3 layers.
1025 ! For a uniform stratification and a huge number of layers uniformly distributed in
1026 ! density, this estimate is too large (as is desired) by a factor of pi^2/6 ~= 1.64.
10270 if (H_top(kf(i)) > 0.0) then
10280 I_Htot = 1.0 / (H_top(kf(i)) + Hf(kf(i),i)) ! = 1.0 / (H_top(K) + H_bot(K)) for all K.
10290 H_bot(kf(i)+1) = 0.0
10300 if (nonBous) then
10310 do K=kf(i),2,-1
10320 H_bot(K) = H_bot(K+1) + Hf(k,i)
1033 dSpVxh_sum = dSpVxh_sum + ((H_top(K) * H_bot(K)) * I_Htot) * &
10340 min(0.0, dSpV_dT(K)*(Tf(k,i)-Tf(k-1,i)) + dSpV_dS(K)*(Sf(k,i)-Sf(k-1,i)))
1035 enddo
1036 else
10370 do K=kf(i),2,-1
10380 H_bot(K) = H_bot(K+1) + Hf(k,i)
1039 drxh_sum = drxh_sum + ((H_top(K) * H_bot(K)) * I_Htot) * &
10400 max(0.0, drho_dT(K)*(Tf(k,i)-Tf(k-1,i)) + drho_dS(K)*(Sf(k,i)-Sf(k-1,i)))
1041 enddo
1042 endif
1043 endif
1044 else
1045 ! This estimate is problematic in that it goes like 1/nz for a large number of layers,
1046 ! but it is an overestimate (as desired) for a small number of layers, by at a factor
1047 ! of (H1+H2)**2/(H1*H2) >= 4 for two thick layers.
10480 if (nonBous) then
10490 do K=2,kf(i)
1050 dSpVxh_sum = dSpVxh_sum + 0.5*(Hf(k-1,i)+Hf(k,i)) * &
10510 min(0.0, dSpV_dT(K)*(Tf(k,i)-Tf(k-1,i)) + dSpV_dS(K)*(Sf(k,i)-Sf(k-1,i)))
1052 enddo
1053 else
10540 do K=2,kf(i)
1055 drxh_sum = drxh_sum + 0.5*(Hf(k-1,i)+Hf(k,i)) * &
10560 max(0.0, drho_dT(K)*(Tf(k,i)-Tf(k-1,i)) + drho_dS(K)*(Sf(k,i)-Sf(k-1,i)))
1057 enddo
1058 endif
1059 endif
1060 else ! Not use_EOS
10610 drxh_sum = 0.0 ; dSpVxh_sum = 0.0
10620 if (better_est) then
10630 H_top(1) = 0.0
10640 do K=2,kf(i) ; H_top(K) = H_top(K-1) + Hf(k-1,i) ; enddo
10650 if (H_top(kf(i)) > 0.0) then
10660 I_Htot = 1.0 / (H_top(kf(i)) + Hf(kf(i),i)) ! = 1.0 / (H_top(K) + H_bot(K)) for all K.
10670 H_bot(kf(i)+1) = 0.0
10680 if (nonBous) then
10690 do K=kf(i),2,-1
10700 H_bot(K) = H_bot(K+1) + Hf(k,i)
1071 dSpVxh_sum = dSpVxh_sum + ((H_top(K) * H_bot(K)) * I_Htot) * &
10720 min(0.0, (Rf(k-1,i)-Rf(k,i)) / (Rf(k,i)*Rf(k-1,i)))
1073 enddo
1074 else
10750 do K=kf(i),2,-1
10760 H_bot(K) = H_bot(K+1) + Hf(k,i)
10770 drxh_sum = drxh_sum + ((H_top(K) * H_bot(K)) * I_Htot) * max(0.0,Rf(k,i)-Rf(k-1,i))
1078 enddo
1079 endif
1080 endif
1081 else
10820 do K=2,kf(i)
10830 drxh_sum = drxh_sum + 0.5*(Hf(k-1,i)+Hf(k,i)) * max(0.0,Rf(k,i)-Rf(k-1,i))
1084 enddo
1085 endif
1086 endif
1087
10880 if (nonBous) then
1089 ! Note that dSpVxh_sum is negative for stable stratification.
10900 cg1_est = H_to_pres * abs(dSpVxh_sum)
1091 else
10920 cg1_est = g_Rho0 * drxh_sum
1093 endif
1094
1095 ! Find gprime across each internal interface, taking care of convective
1096 ! instabilities by merging layers.
10970 if (cg1_est > cg1_min2) then
1098 ! Merge layers to eliminate convective instabilities or exceedingly
1099 ! small reduced gravities. Merging layers reduces the estimated wave speed by
1100 ! (rho(2)-rho(1))*h(1)*h(2) / H_tot.
11010 if (use_EOS) then
11020 kc = 1
11030 Hc(1) = Hf(1,i) ; dzc(1) = dzf(1,i) ; Tc(1) = Tf(1,i) ; Sc(1) = Sf(1,i)
11040 do k=2,kf(i)
11050 if (better_est .and. nonBous) then
1106 merge = ((dSpV_dT(K)*(Tc(kc)-Tf(k,i)) + dSpV_dS(K)*(Sc(kc)-Sf(k,i))) * &
11070 ((Hc(kc) * Hf(k,i))*I_Htot) < abs(2.0 * tol_merge * dSpVxh_sum))
11080 elseif (better_est) then
1109 merge = ((drho_dT(K)*(Tf(k,i)-Tc(kc)) + drho_dS(K)*(Sf(k,i)-Sc(kc))) * &
11100 ((Hc(kc) * Hf(k,i))*I_Htot) < 2.0 * tol_merge*drxh_sum)
11110 elseif (nonBous) then
1112 merge = ((dSpV_dT(K)*(Tc(kc)-Tf(k,i)) + dSpV_dS(K)*(Sc(kc)-Sf(k,i))) * &
11130 (Hc(kc) + Hf(k,i)) < abs(2.0 * tol_merge * dSpVxh_sum))
1114 else
1115 merge = ((drho_dT(K)*(Tf(k,i)-Tc(kc)) + drho_dS(K)*(Sf(k,i)-Sc(kc))) * &
11160 (Hc(kc) + Hf(k,i)) < 2.0 * tol_merge*drxh_sum)
1117 endif
11180 if (merge) then
1119 ! Merge this layer with the one above and backtrack.
11200 I_Hnew = 1.0 / (Hc(kc) + Hf(k,i))
11210 Tc(kc) = (Hc(kc)*Tc(kc) + Hf(k,i)*Tf(k,i)) * I_Hnew
11220 Sc(kc) = (Hc(kc)*Sc(kc) + Hf(k,i)*Sf(k,i)) * I_Hnew
11230 Hc(kc) = Hc(kc) + Hf(k,i)
11240 dzc(kc) = dzc(kc) + dzf(k,i)
1125 ! Backtrack to remove any convective instabilities above... Note
1126 ! that the tolerance is a factor of two larger, to avoid limit how
1127 ! far back we go.
11280 do K2=kc,2,-1
11290 if (better_est .and. nonBous) then
1130 merge = ( (dSpV_dT(K2)*(Tc(k2-1)-Tc(k2)) + dSpV_dS(K2)*(Sc(k2-1)-Sc(k2))) * &
11310 ((Hc(k2) * Hc(k2-1))*I_Htot) < abs(tol_merge * dSpVxh_sum) )
11320 elseif (better_est) then
1133 merge = ((drho_dT(K2)*(Tc(k2)-Tc(k2-1)) + drho_dS(K2)*(Sc(k2)-Sc(k2-1))) * &
11340 ((Hc(k2) * Hc(k2-1))*I_Htot) < tol_merge*drxh_sum)
11350 elseif (nonBous) then
1136 merge = ( (dSpV_dT(K2)*(Tc(k2-1)-Tc(k2)) + dSpV_dS(K2)*(Sc(k2-1)-Sc(k2))) * &
11370 (Hc(k2) + Hc(k2-1)) < abs(tol_merge * dSpVxh_sum) )
1138 else
1139 merge = ((drho_dT(K2)*(Tc(k2)-Tc(k2-1)) + drho_dS(K2)*(Sc(k2)-Sc(k2-1))) * &
11400 (Hc(k2) + Hc(k2-1)) < tol_merge*drxh_sum)
1141 endif
11420 if (merge) then
1143 ! Merge the two bottommost layers. At this point kc = k2.
11440 I_Hnew = 1.0 / (Hc(kc) + Hc(kc-1))
11450 Tc(kc-1) = (Hc(kc)*Tc(kc) + Hc(kc-1)*Tc(kc-1)) * I_Hnew
11460 Sc(kc-1) = (Hc(kc)*Sc(kc) + Hc(kc-1)*Sc(kc-1)) * I_Hnew
11470 Hc(kc-1) = Hc(kc) + Hc(kc-1)
11480 dzc(kc-1) = dzc(kc) + dzc(kc-1)
11490 kc = kc - 1
11500 else ; exit ; endif
1151 enddo
1152 else
1153 ! Add a new layer to the column.
11540 kc = kc + 1
11550 if (nonBous) then
11560 dSpV_dS(Kc) = dSpV_dS(K) ; dSpV_dT(Kc) = dSpV_dT(K)
1157 else
11580 drho_dS(Kc) = drho_dS(K) ; drho_dT(Kc) = drho_dT(K)
1159 endif
11600 Tc(kc) = Tf(k,i) ; Sc(kc) = Sf(k,i) ; Hc(kc) = Hf(k,i) ; dzc(kc) = dzf(k,i)
1161 endif
1162 enddo
1163 ! At this point there are kc layers and the gprimes should be positive.
11640 if (nonBous) then
11650 do K=2,kc
11660 gprime(K) = H_to_pres * (dSpV_dT(K)*(Tc(k-1)-Tc(k)) + dSpV_dS(K)*(Sc(k-1)-Sc(k)))
1167 enddo
1168 else
11690 do K=2,kc
11700 gprime(K) = g_Rho0 * (drho_dT(K)*(Tc(k)-Tc(k-1)) + drho_dS(K)*(Sc(k)-Sc(k-1)))
1171 enddo
1172 endif
1173 else ! .not. (use_EOS)
1174 ! Do the same with density directly...
11750 kc = 1
11760 Hc(1) = Hf(1,i) ; dzc(1) = dzf(1,i) ; Rc(1) = Rf(1,i)
11770 do k=2,kf(i)
11780 if (nonBous .and. better_est) then
1179 merge = ((Rf(k,i) - Rc(kc)) * ((Hc(kc) * Hf(k,i))*I_Htot) < &
11800 (Rc(kc)*Rf(k,i)) * abs(2.0 * tol_merge * dSpVxh_sum))
11810 elseif (nonBous) then
1182 merge = ((Rf(k,i) - Rc(kc)) * (Hc(kc) + Hf(k,i)) < &
11830 (Rc(kc)*Rf(k,i)) * abs(2.0 * tol_merge * dSpVxh_sum))
11840 elseif (better_est) then
11850 merge = ((Rf(k,i) - Rc(kc)) * ((Hc(kc) * Hf(k,i))*I_Htot) < 2.0*tol_merge*drxh_sum)
1186 else
11870 merge = ((Rf(k,i) - Rc(kc)) * (Hc(kc) + Hf(k,i)) < 2.0*tol_merge*drxh_sum)
1188 endif
11890 if (merge) then
1190 ! Merge this layer with the one above and backtrack.
11910 Rc(kc) = (Hc(kc)*Rc(kc) + Hf(k,i)*Rf(k,i)) / (Hc(kc) + Hf(k,i))
11920 Hc(kc) = Hc(kc) + Hf(k,i)
11930 dzc(kc) = dzc(kc) + dzf(k,i)
1194 ! Backtrack to remove any convective instabilities above... Note
1195 ! that the tolerance is a factor of two larger, to avoid limit how
1196 ! far back we go.
11970 do k2=kc,2,-1
11980 if (better_est) then
11990 merge = ((Rc(k2)-Rc(k2-1)) * ((Hc(k2) * Hc(k2-1))*I_Htot) < tol_merge*drxh_sum)
1200 else
12010 merge = ((Rc(k2)-Rc(k2-1)) * (Hc(k2)+Hc(k2-1)) < tol_merge*drxh_sum)
1202 endif
12030 if (merge) then
1204 ! Merge the two bottommost layers. At this point kc = k2.
12050 Rc(kc-1) = (Hc(kc)*Rc(kc) + Hc(kc-1)*Rc(kc-1)) / (Hc(kc) + Hc(kc-1))
12060 Hc(kc-1) = Hc(kc) + Hc(kc-1)
12070 dzc(kc-1) = dzc(kc) + dzc(kc-1)
12080 kc = kc - 1
12090 else ; exit ; endif
1210 enddo
1211 else
1212 ! Add a new layer to the column.
12130 kc = kc + 1
12140 Rc(kc) = Rf(k,i) ; Hc(kc) = Hf(k,i) ; dzc(kc) = dzf(k,i)
1215 endif
1216 enddo
1217 ! At this point there are kc layers and the gprimes should be positive.
12180 if (nonBous) then
12190 do K=2,kc
12200 gprime(K) = H_to_pres * (Rc(k) - Rc(k-1)) / (Rc(k) * Rc(k-1))
1221 enddo
1222 else
12230 do K=2,kc
12240 gprime(K) = g_Rho0 * (Rc(k)-Rc(k-1))
1225 enddo
1226 endif
1227 endif ! use_EOS
1228
1229 !-----------------NOW FIND WAVE SPEEDS---------------------------------------
1230 ! ig = i + G%idg_offset ; jg = j + G%jdg_offset
1231 ! Sum the contributions from all of the interfaces to give an over-estimate
1232 ! of the first-mode wave speed. Also populate Igl and Igu which are the
1233 ! non-leading diagonals of the tridiagonal matrix.
12340 if (kc >= 2) then
1235 ! initialize speed2_tot
12360 speed2_tot = 0.0
12370 if (better_est) then
12380 H_top(1) = 0.0 ; H_bot(kc+1) = 0.0
12390 do K=2,kc+1 ; H_top(K) = H_top(K-1) + Hc(k-1) ; enddo
12400 do K=kc,2,-1 ; H_bot(K) = H_bot(K+1) + Hc(k) ; enddo
12410 I_Htot = 0.0 ; if (H_top(kc+1) > 0.0) I_Htot = 1.0 / H_top(kc+1)
1242 endif
1243
1244 ! Calculate Igu, Igl, depth, and N2 at each interior interface
1245 ! [excludes surface (K=1) and bottom (K=kc+1)]
12460 Igl(:) = 0.
12470 Igu(:) = 0.
12480 N2(:) = 0.
1249
12500 do K=2,kc
12510 Igl(K) = 1.0 / (gprime(K)*Hc(k)) ; Igu(K) = 1.0 / (gprime(K)*Hc(k-1))
12520 if (nonBous) then
1253 N2(K) = 2.0*US%L_to_Z**2*gprime(K) * (Hc(k) + Hc(k-1)) / & ! Units are [T-2 ~> s-2]
12540 (dzc(k) + dzc(k-1))**2
1255 else
12560 N2(K) = 2.0*US%L_to_Z**2*GV%Z_to_H*gprime(K) / (dzc(k) + dzc(k-1)) ! Units are [T-2 ~> s-2]
1257 endif
12580 if (better_est) then
12590 speed2_tot = speed2_tot + gprime(K)*((H_top(K) * H_bot(K)) * I_Htot)
1260 else
12610 speed2_tot = speed2_tot + gprime(K)*(Hc(k-1)+Hc(k))
1262 endif
1263 enddo
1264
1265 ! Set stratification for surface and bottom (setting equal to nearest interface for now)
12660 N2(1) = N2(2) ; N2(kc+1) = N2(kc)
1267 ! set bottom stratification
12680 Nb(i,j) = sqrt(N2(kc+1))
1269
1270 ! Under estimate the first eigenvalue (overestimate the speed) to start with.
12710 lam_1 = 1.0 / speed2_tot
1272
1273 ! init and first guess for mode structure
12740 mode_struct(:) = 0.
12750 mode_struct_fder(:) = 0.
12760 mode_struct(2:kc) = 1. ! Uniform flow, first guess
12770 modal_structure(:) = 0.
12780 modal_structure_fder(:) = 0.
1279
1280 ! Find the first eigen value
12810 do itt=1,max_itt
1282 ! calculate the determinant of (A-lam_1*I)
12830 call tridiag_det(Igu, Igl, 2, kc, lam_1, det, ddet, row_scale=c2_scale)
1284
1285 ! If possible, use Newton's method iteration to find a new estimate of lam_1
1286 !det = det_it(itt) ; ddet = ddet_it(itt)
12870 if ((ddet >= 0.0) .or. (-det > -0.5*lam_1*ddet)) then
1288 ! lam_1 was not an under-estimate, as intended, so Newton's method
1289 ! may not be reliable; lam_1 must be reduced, but not by more than half.
12900 lam_1 = 0.5 * lam_1
12910 dlam = -lam_1
1292 else ! Newton's method is OK.
12930 dlam = - det / ddet
12940 lam_1 = lam_1 + dlam
1295 endif
1296
12970 call tdma6(kc-1, Igu(2:kc), Igl(2:kc), lam_1, mode_struct(2:kc))
1298 ! Note that tdma6 changes the units of mode_struct to [L2 T-2 ~> m2 s-2]
1299 ! apply BC
13000 mode_struct(1) = 0.
13010 mode_struct(kc+1) = 0.
1302
1303 ! renormalization of the integral of the profile
13040 w2avg = 0.0
13050 do k=1,kc
13060 w2avg = w2avg + 0.5*(mode_struct(K)**2+mode_struct(K+1)**2)*Hc(k) ! [H L4 T-4 ~> m5 s-4 or kg m2 s-4]
1307 enddo
13080 renorm = sqrt(htot(i)*a_int/w2avg) ! [T2 L-2 ~> s2 m-2]
13090 do K=1,kc+1 ; mode_struct(K) = renorm * mode_struct(K) ; enddo
1310 ! after renorm, mode_struct is again [nondim]
13110 if (abs(dlam) < tol_solve*lam_1) exit
1312 enddo
1313
13140 if (lam_1 > 0.0) cn(i,j,1) = 1.0 / sqrt(lam_1)
1315
1316 ! sign of wave structure is irrelevant, flip to positive if needed
13170 if (mode_struct(2)<0.) then
13180 mode_struct(2:kc) = -1. * mode_struct(2:kc)
1319 endif
1320
1321 ! vertical derivative of w at interfaces lives on the layer points
13220 do k=1,kc
13230 mode_struct_fder(k) = (mode_struct(k) - mode_struct(k+1)) / dzc(k)
1324 enddo
1325
1326 ! boundary condition for derivative is no-gradient
13270 do k=kc+1,nz
13280 mode_struct_fder(k) = mode_struct_fder(kc)
1329 enddo
1330
1331 ! now save maximum value and bottom value
13320 u_struct_bot(i,j,1) = mode_struct_fder(kc)
13330 u_struct_max(i,j,1) = maxval(abs(mode_struct_fder(1:kc)))
1334
1335 ! Calculate terms for vertically integrated energy equation
13360 do k=1,kc
13370 mode_struct_fder_sq(k) = mode_struct_fder(k)**2
1338 enddo
13390 do K=1,kc+1
13400 mode_struct_sq(K) = mode_struct(K)**2
1341 enddo
1342
1343 ! sum over layers for quantities defined on layer
13440 do k=1,kc
13450 int_U2(i,j,1) = int_U2(i,j,1) + mode_struct_fder_sq(k) * Hc(k)
1346 enddo
1347
1348 ! vertical integration with Trapezoidal rule for values at interfaces
13490 do K=1,kc
13500 int_w2(i,j,1) = int_w2(i,j,1) + 0.5*(mode_struct_sq(K)+mode_struct_sq(K+1)) * Hc(k)
1351 int_N2w2(i,j,1) = int_N2w2(i,j,1) + 0.5*(mode_struct_sq(K)*N2(K) + &
13520 mode_struct_sq(K+1)*N2(K+1)) * Hc(k)
1353 enddo
1354
1355 ! for w (diag) interpolate onto all interfaces
1356 call interpolate_column(kc, Hc(1:kc), mode_struct(1:kc+1), &
13570 nz, h(i,j,:), modal_structure(:), .false.)
1358
1359 ! for u (remap) onto all layers
1360 call remapping_core_h(CS%remap_CS, kc, Hc(1:kc), mode_struct_fder(1:kc), &
13610 nz, h(i,j,:), modal_structure_fder(:))
1362
1363 ! write the wave structure
13640 do k=1,nz+1
13650 w_struct(i,j,k,1) = modal_structure(k)
1366 enddo
1367
13680 do k=1,nz
13690 u_struct(i,j,k,1) = modal_structure_fder(k)
1370 enddo
1371
1372 ! Find other eigen values if c1 is of significant magnitude, > cn_thresh
13730 nrootsfound = 0 ! number of extra roots found (not including 1st root)
13740 if ((nmodes > 1) .and. (kc >= nmodes+1) .and. (cn(i,j,1) > CS%c1_thresh)) then
1375 ! Set the range to look for the other desired eigen values
1376 ! set min value just greater than the 1st root (found above)
13770 lamMin = lam_1*(1.0 + tol_solve)
1378 ! set max value based on a low guess at wavespeed for highest mode
13790 speed2_min = (reduct_factor*cn(i,j,1)/real(nmodes))**2
13800 lamMax = 1.0 / speed2_min
1381 ! set width of interval (not sure about this - BDM)
13820 lamInc = 0.5*lam_1
1383 ! set number of intervals within search range
13840 numint = nint((lamMax - lamMin)/lamInc)
1385
1386 ! Find intervals containing zero-crossings (roots) of the determinant
1387 ! that are beyond the first root
1388
1389 ! find det_l of first interval (det at left endpoint)
13900 call tridiag_det(Igu, Igl, 2, kc, lamMin, det_l, ddet_l, row_scale=c2_scale)
1391 ! move interval window looking for zero-crossings************************
13920 do iint=1,numint
13930 xr = lamMin + lamInc * iint
13940 xl = xr - lamInc
13950 call tridiag_det(Igu, Igl, 2, kc, xr, det_r, ddet_r, row_scale=c2_scale)
13960 if (det_l*det_r < 0.0) then ! if function changes sign
13970 if (det_l*ddet_l < 0.0) then ! if function at left is headed to zero
13980 nrootsfound = nrootsfound + 1
13990 xbl(nrootsfound) = xl
14000 xbr(nrootsfound) = xr
1401 else
1402 ! function changes sign but has a local max/min in interval,
1403 ! try subdividing interval as many times as necessary (or sub_it_max).
1404 ! loop that increases number of subintervals:
1405 !call MOM_error(WARNING, "determinant changes sign "// &
1406 ! "but has a local max/min in interval; "//&
1407 ! "reduce increment in lam.")
1408 ! begin subdivision loop -------------------------------------------
14090 sub_rootfound = .false. ! initialize
14100 do sub_it=1,sub_it_max
14110 nsub = 2**sub_it ! number of subintervals; nsub=2,4,8,...
1412 ! loop over each subinterval:
14130 do sub=1,nsub-1,2 ! only check odds; sub = 1; 1,3; 1,3,5,7; ...
14140 xl_sub = xl + lamInc/(nsub)*sub
1415 call tridiag_det(Igu, Igl, 2, kc, xl_sub, det_sub, ddet_sub, &
14160 row_scale=c2_scale)
14170 if (det_sub*det_r < 0.0) then ! if function changes sign
14180 if (det_sub*ddet_sub < 0.0) then ! if function at left is headed to zero
14190 sub_rootfound = .true.
14200 nrootsfound = nrootsfound + 1
14210 xbl(nrootsfound) = xl_sub
14220 xbr(nrootsfound) = xr
14230 exit ! exit sub loop
1424 endif ! headed toward zero
1425 endif ! sign change
1426 enddo ! sub-loop
14270 if (sub_rootfound) exit ! root has been found, exit sub_it loop
1428 ! Otherwise, function changes sign but has a local max/min in one of the
1429 ! sub intervals, try subdividing again unless sub_it_max has been reached.
14300 if (sub_it == sub_it_max) then
1431 call MOM_error(WARNING, "wave_speed: root not found "// &
1432 "after sub_it_max subdivisions of original "// &
14330 "interval.")
1434 endif ! sub_it == sub_it_max
1435 enddo ! sub_it-loop-------------------------------------------------
1436 endif ! det_l*ddet_l < 0.0
1437 endif ! det_l*det_r < 0.0
1438 ! exit iint-loop if all desired roots have been found
14390 if (nrootsfound >= nmodes-1) then
1440 ! exit if all additional roots found
14410 exit
14420 elseif (iint == numint) then
1443 ! oops, lamMax not large enough - could add code to increase (BDM)
1444 ! set unfound modes to zero for now (BDM)
1445 ! cn(i,j,nrootsfound+2:nmodes) = 0.0
1446 else
1447 ! else shift interval and keep looking until nmodes or numint is reached
14480 det_l = det_r
14490 ddet_l = ddet_r
1450 endif
1451 enddo ! iint-loop
1452
1453 ! Use Newton's method to find the roots within the identified windows
14540 do m=1,nrootsfound ! loop over the root-containing widows (excluding 1st mode)
14550 lam_n = xbl(m) ! first guess is left edge of window
1456
1457 ! init and first guess for mode structure
14580 mode_struct(:) = 0.
14590 mode_struct_fder(:) = 0.
14600 mode_struct(2:kc) = 1. ! Uniform flow, first guess
14610 modal_structure(:) = 0.
14620 modal_structure_fder(:) = 0.
1463
14640 do itt=1,max_itt
1465 ! calculate the determinant of (A-lam_n*I)
14660 call tridiag_det(Igu, Igl, 2, kc, lam_n, det, ddet, row_scale=c2_scale)
1467 ! Use Newton's method to find a new estimate of lam_n
14680 dlam = - det / ddet
14690 lam_n = lam_n + dlam
1470
14710 call tdma6(kc-1, Igu(2:kc), Igl(2:kc), lam_n, mode_struct(2:kc))
1472 ! Note that tdma6 changes the units of mode_struct to [L2 T-2 ~> m2 s-2]
1473 ! apply BC
14740 mode_struct(1) = 0.
14750 mode_struct(kc+1) = 0.
1476
1477 ! renormalization of the integral of the profile
14780 w2avg = 0.0
14790 do k=1,kc
14800 w2avg = w2avg + 0.5*(mode_struct(K)**2+mode_struct(K+1)**2)*Hc(k)
1481 enddo
14820 renorm = sqrt(htot(i)*a_int/w2avg)
14830 do K=1,kc+1 ; mode_struct(K) = renorm * mode_struct(K) ; enddo
1484
14850 if (abs(dlam) < tol_solve*lam_1) exit
1486 enddo ! itt-loop
1487
1488 ! calculate nth mode speed
14890 if (lam_n > 0.0) cn(i,j,m+1) = 1.0 / sqrt(lam_n)
1490
1491 ! sign is irrelevant, flip to positive if needed
14920 if (mode_struct(2)<0.) then
14930 mode_struct(2:kc) = -1. * mode_struct(2:kc)
1494 endif
1495
1496 ! derivative of vertical profile (i.e. dw/dz) is evaluated at the layer point
14970 do k=1,kc
14980 mode_struct_fder(k) = (mode_struct(k) - mode_struct(k+1)) / dzc(k)
1499 enddo
1500
1501 ! boundary condition for 1st derivative is no-gradient
15020 do k=kc+1,nz
15030 mode_struct_fder(k) = mode_struct_fder(kc)
1504 enddo
1505
1506 ! now save maximum value and bottom value
15070 u_struct_bot(i,j,m) = mode_struct_fder(kc)
15080 u_struct_max(i,j,m) = maxval(abs(mode_struct_fder(1:kc)))
1509
1510 ! Calculate terms for vertically integrated energy equation
15110 do k=1,kc
15120 mode_struct_fder_sq(k) = mode_struct_fder(k)**2
1513 enddo
15140 do K=1,kc+1
15150 mode_struct_sq(K) = mode_struct(K)**2
1516 enddo
1517
1518 ! sum over layers for integral of quantities defined at layer points
15190 do k=1,kc
15200 int_U2(i,j,m) = int_U2(i,j,m) + mode_struct_fder_sq(k) * Hc(k)
1521 enddo
1522
1523 ! vertical integration with Trapezoidal rule for quantities on interfaces
15240 do K=1,kc
15250 int_w2(i,j,m) = int_w2(i,j,m) + 0.5*(mode_struct_sq(K)+mode_struct_sq(K+1)) * Hc(k)
1526 int_N2w2(i,j,m) = int_N2w2(i,j,m) + 0.5*(mode_struct_sq(K)*N2(K) + &
15270 mode_struct_sq(K+1)*N2(K+1)) * Hc(k)
1528 enddo
1529
1530 ! for w (diag) interpolate onto all interfaces
1531 call interpolate_column(kc, Hc(1:kc), mode_struct(1:kc+1), &
15320 nz, h(i,j,:), modal_structure(:), .false.)
1533
1534 ! for u (remap) onto all layers
1535 call remapping_core_h(CS%remap_CS, kc, Hc(1:kc), mode_struct_fder(1:kc), &
15360 nz, h(i,j,:), modal_structure_fder(:))
1537
1538 ! write the wave structure
1539 ! note that m=1 solves for 2nd mode,...
15400 do k=1,nz+1
15410 w_struct(i,j,k,m+1) = modal_structure(k)
1542 enddo
1543
15440 do k=1,nz
15450 u_struct(i,j,k,m+1) = modal_structure_fder(k)
1546 enddo
1547
1548 enddo ! n-loop
1549 endif ! if nmodes>1 .and. kc>nmodes .and. c1>c1_thresh
1550 endif ! if more than 2 layers
1551 endif ! if drxh_sum < 0
1552 endif ! if not land
1553 enddo ! i-loop
1554 enddo ! j-loop
1555
15560end subroutine wave_speeds
1557
1558!> Calculate the determinant of a tridiagonal matrix with diagonals a,b-lam,c and its derivative
1559!! with lam, where lam is constant across rows. Only the ratio of det to its derivative and their
1560!! signs are typically used, so internal rescaling by consistent factors are used to avoid
1561!! over- or underflow.
1562470070subroutine tridiag_det(a, c, ks, ke, lam, det, ddet, row_scale)
1563 real, dimension(:), intent(in) :: a !< Lower diagonal of matrix (first entry unused) [T2 L-2 ~> s2 m-2]
1564 real, dimension(:), intent(in) :: c !< Upper diagonal of matrix (last entry unused) [T2 L-2 ~> s2 m-2]
1565 integer, intent(in) :: ks !< Starting index to use in determinant
1566 integer, intent(in) :: ke !< Ending index to use in determinant
1567 real, intent(in) :: lam !< Value subtracted from b [T2 L-2 ~> s2 m-2]
1568 real, intent(out):: det !< Determinant of the matrix in dynamically rescaled units that
1569 !! depend on the number of rows and the cumulative magnitude of
1570 !! det and are therefore difficult to interpret, but the units
1571 !! of det/ddet are always in [T2 L-2 ~> s2 m-2]
1572 real, intent(out):: ddet !< Derivative of determinant with lam in units that are dynamically
1573 !! rescaled along with those of det, such that the units of
1574 !! det/ddet are always in [T2 L-2 ~> s2 m-2]
1575 real, intent(in) :: row_scale !< A scaling factor of the rows of the matrix to
1576 !! limit the growth of the determinant [L2 s2 T-2 m-2 ~> 1]
1577 ! Local variables
1578 real :: detKm1, detKm2 ! Cumulative value of the determinant for the previous two layers in units
1579 ! that vary with the number of layers that have been worked on [various]
1580 real :: ddetKm1, ddetKm2 ! Derivative of the cumulative determinant with lam for the previous two
1581 ! layers [various], but the units of detKm1/ddetKm1 are [T2 L-2 ~> s2 m-2]
1582 real, parameter :: rescale = 1024.0**4 ! max value of determinant allowed before rescaling [nondim]
1583 real :: I_rescale ! inverse of rescale [nondim]
1584 integer :: k ! row (layer interface) index
1585
1586470070 I_rescale = 1.0 / rescale
1587
1588470070 detKm1 = 1.0 ; ddetKm1 = 0.0
1589470070 det = (a(ks)+c(ks)) - lam ; ddet = -1.0
159012957382 do k=ks+1,ke
1591 ! Shift variables and rescale rows to avoid over- or underflow.
159212487312 detKm2 = row_scale*detKm1 ; ddetKm2 = row_scale*ddetKm1
159312487312 detKm1 = row_scale*det ; ddetKm1 = row_scale*ddet
1594
159512487312 det = ((a(k)+c(k))-lam)*detKm1 - (a(k)*c(k-1))*detKm2
159612487312 ddet = ((a(k)+c(k))-lam)*ddetKm1 - (a(k)*c(k-1))*ddetKm2 - detKm1
1597
1598 ! Rescale det & ddet if det is getting too large or too small.
159912957382 if (abs(det) > rescale) then
16000 det = I_rescale*det ; detKm1 = I_rescale*detKm1
16010 ddet = I_rescale*ddet ; ddetKm1 = I_rescale*ddetKm1
160212487312 elseif (abs(det) < I_rescale) then
16035761367 det = rescale*det ; detKm1 = rescale*detKm1
16045761367 ddet = rescale*ddet ; ddetKm1 = rescale*ddetKm1
1605 endif
1606 enddo
1607
1608470070end subroutine tridiag_det
1609
1610!> Initialize control structure for MOM_wave_speed
16112subroutine wave_speed_init(CS, GV, use_ebt_mode, mono_N2_column_fraction, mono_N2_depth, remap_answers_2018, &
1612 remap_answer_date, better_speed_est, om4_remap_via_sub_cells, &
1613 min_speed, wave_speed_tol, c1_thresh)
1614 type(wave_speed_CS), intent(inout) :: CS !< Wave speed control struct
1615 type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure
1616 logical, optional, intent(in) :: use_ebt_mode !< If true, use the equivalent
1617 !! barotropic mode instead of the first baroclinic mode.
1618 real, optional, intent(in) :: mono_N2_column_fraction !< The lower fraction of water column over
1619 !! which N2 is limited as monotonic for the purposes of
1620 !! calculating the vertical modal structure [nondim].
1621 real, optional, intent(in) :: mono_N2_depth !< The depth below which N2 is limited
1622 !! as monotonic for the purposes of calculating the
1623 !! vertical modal structure [H ~> m or kg m-2].
1624 logical, optional, intent(in) :: remap_answers_2018 !< If true, use the order of arithmetic and expressions
1625 !! that recover the remapping answers from 2018. Otherwise
1626 !! use more robust but mathematically equivalent expressions.
1627 integer, optional, intent(in) :: remap_answer_date !< The vintage of the order of arithmetic and expressions
1628 !! to use for remapping. Values below 20190101 recover the remapping
1629 !! answers from 2018, while higher values use more robust
1630 !! forms of the same remapping expressions.
1631 logical, optional, intent(in) :: better_speed_est !< If true, use a more robust estimate of the first
1632 !! mode speed as the starting point for iterations.
1633 logical, optional, intent(in) :: om4_remap_via_sub_cells !< Use the OM4-era ramap_via_sub_cells
1634 !! for calculating the EBT structure
1635 real, optional, intent(in) :: min_speed !< If present, set a floor in the first mode speed
1636 !! below which 0 is returned [L T-1 ~> m s-1].
1637 real, optional, intent(in) :: wave_speed_tol !< The fractional tolerance for finding the
1638 !! wave speeds [nondim]
1639 real, optional, intent(in) :: c1_thresh !< A minimal value of the first mode internal wave speed
1640 !! below which all higher mode speeds are not calculated but are
1641 !! simply reported as 0 [L T-1 ~> m s-1]. A non-negative value
1642 !! must be specified for wave_speeds to be used (but not wave_speed).
1643
1644 ! This include declares and sets the variable "version".
1645# include "version_variable.h"
1646 character(len=40) :: mdl = "MOM_wave_speed" ! This module's name.
1647
16482 CS%initialized = .true.
1649
1650 ! Write all relevant parameters to the model log.
16512 call log_version(mdl, version)
1652
1653 call wave_speed_set_param(CS, use_ebt_mode=use_ebt_mode, mono_N2_column_fraction=mono_N2_column_fraction, &
1654 mono_N2_depth=mono_N2_depth, better_speed_est=better_speed_est, &
1655 min_speed=min_speed, wave_speed_tol=wave_speed_tol, &
1656 remap_answers_2018=remap_answers_2018, remap_answer_date=remap_answer_date, &
16572 c1_thresh=c1_thresh)
1658
1659 ! The following remapping is only used for wave_speed with pre-2019 answers.
16602 if (CS%remap_answer_date < 20190101) &
1661 call initialize_remapping(CS%remap_2018_CS, 'PLM', boundary_extrapolation=.false., &
1662 om4_remap_via_sub_cells=om4_remap_via_sub_cells, &
1663 answer_date=CS%remap_answer_date, &
16640 h_neglect=1.0e-30*GV%m_to_H, h_neglect_edge=1.0e-10*GV%m_to_H)
1665
1666 ! This is used in wave_speeds in all cases, and in wave_speed with newer answers.
1667 call initialize_remapping(CS%remap_CS, 'PLM', boundary_extrapolation=.false., &
1668 om4_remap_via_sub_cells=om4_remap_via_sub_cells, &
1669 answer_date=CS%remap_answer_date, &
16702 h_neglect=GV%H_subroundoff, h_neglect_edge=GV%H_subroundoff)
1671
16722end subroutine wave_speed_init
1673
1674!> Sets internal parameters for MOM_wave_speed
16752subroutine wave_speed_set_param(CS, use_ebt_mode, mono_N2_column_fraction, mono_N2_depth, remap_answers_2018, &
1676 remap_answer_date, better_speed_est, min_speed, wave_speed_tol, c1_thresh)
1677 type(wave_speed_CS), intent(inout) :: CS
1678 !< Control structure for MOM_wave_speed
1679 logical, optional, intent(in) :: use_ebt_mode !< If true, use the equivalent
1680 !! barotropic mode instead of the first baroclinic mode.
1681 real, optional, intent(in) :: mono_N2_column_fraction !< The lower fraction of water column over
1682 !! which N2 is limited as monotonic for the purposes of
1683 !! calculating the vertical modal structure [nondim].
1684 real, optional, intent(in) :: mono_N2_depth !< The depth below which N2 is limited
1685 !! as monotonic for the purposes of calculating the
1686 !! vertical modal structure [H ~> m or kg m-2].
1687 logical, optional, intent(in) :: remap_answers_2018 !< If true, use the order of arithmetic and expressions
1688 !! that recover the remapping answers from 2018. Otherwise
1689 !! use more robust but mathematically equivalent expressions.
1690 integer, optional, intent(in) :: remap_answer_date !< The vintage of the order of arithmetic and expressions
1691 !! to use for remapping. Values below 20190101 recover the remapping
1692 !! answers from 2018, while higher values use more robust
1693 !! forms of the same remapping expressions.
1694 logical, optional, intent(in) :: better_speed_est !< If true, use a more robust estimate of the first
1695 !! mode speed as the starting point for iterations.
1696 real, optional, intent(in) :: min_speed !< If present, set a floor in the first mode speed
1697 !! below which 0 is returned [L T-1 ~> m s-1].
1698 real, optional, intent(in) :: wave_speed_tol !< The fractional tolerance for finding the
1699 !! wave speeds [nondim]
1700 real, optional, intent(in) :: c1_thresh !< A minimal value of the first mode internal wave speed
1701 !! below which all higher mode speeds are not calculated but are
1702 !! simply reported as 0 [L T-1 ~> m s-1]. A non-negative value
1703 !! must be specified for wave_speeds to be used (but not wave_speed).
1704
17052 if (present(use_ebt_mode)) CS%use_ebt_mode = use_ebt_mode
17062 if (present(mono_N2_column_fraction)) CS%mono_N2_column_fraction = mono_N2_column_fraction
17072 if (present(mono_N2_depth)) CS%mono_N2_depth = mono_N2_depth
17082 if (present(remap_answers_2018)) then
17090 if (remap_answers_2018) then
17100 CS%remap_answer_date = 20181231
1711 else
17120 CS%remap_answer_date = 20190101
1713 endif
1714 endif
17152 if (present(remap_answer_date)) CS%remap_answer_date = remap_answer_date
17162 if (present(better_speed_est)) CS%better_cg1_est = better_speed_est
17172 if (present(min_speed)) CS%min_speed2 = min_speed**2
17182 if (present(wave_speed_tol)) CS%wave_speed_tol = wave_speed_tol
17192 if (present(c1_thresh)) CS%c1_thresh = c1_thresh
1720
17212end subroutine wave_speed_set_param
1722
1723!> \namespace mom_wave_speed
1724
1725!!
1726!! Subroutine wave_speed() solves for the first baroclinic mode wave speed. (It could
1727!! solve for all the wave speeds, but the iterative approach taken here means
1728!! that this is not particularly efficient.)
1729!!
1730!! If `e(k)` is the perturbation interface height, this means solving for the
1731!! smallest eigenvalue (`lam` = 1/c^2) of the system
1732!!
1733!! \verbatim
1734!! -Igu(k)*e(k-1) + (Igu(k)+Igl(k)-lam)*e(k) - Igl(k)*e(k+1) = 0.0
1735!! \endverbatim
1736!!
1737!! with rigid lid boundary conditions e(1) = e(nz+1) = 0.0 giving
1738!!
1739!! \verbatim
1740!! (Igu(2)+Igl(2)-lam)*e(2) - Igl(2)*e(3) = 0.0
1741!! -Igu(nz)*e(nz-1) + (Igu(nz)+Igl(nz)-lam)*e(nz) = 0.0
1742!! \endverbatim
1743!!
1744!! Here
1745!! \verbatim
1746!! Igl(k) = 1.0/(gprime(K)*h(k)) ; Igu(k) = 1.0/(gprime(K)*h(k-1))
1747!! \endverbatim
1748!!
1749!! Alternately, these same eigenvalues can be found from the second smallest
1750!! eigenvalue of the Montgomery potential (M(k)) calculation:
1751!!
1752!! \verbatim
1753!! -Igl(k)*M(k-1) + (Igl(k)+Igu(k+1)-lam)*M(k) - Igu(k+1)*M(k+1) = 0.0
1754!! \endverbatim
1755!!
1756!! with rigid lid and flat bottom boundary conditions
1757!!
1758!! \verbatim
1759!! (Igu(2)-lam)*M(1) - Igu(2)*M(2) = 0.0
1760!! -Igl(nz)*M(nz-1) + (Igl(nz)-lam)*M(nz) = 0.0
1761!! \endverbatim
1762!!
1763!! Note that the barotropic mode has been eliminated from the rigid lid
1764!! interface height equations, hence the matrix is one row smaller. Without
1765!! the rigid lid, the top boundary condition is simpler to implement with
1766!! the M equations.
1767
17680end module MOM_wave_speed