← back to index

src/core/MOM_density_integrals.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!> Provides integrals of density
6module MOM_density_integrals
7
8use MOM_EOS, only : EOS_type
9use MOM_EOS, only : EOS_quadrature, EOS_domain
10use MOM_EOS, only : analytic_int_density_dz
11use MOM_EOS, only : analytic_int_specific_vol_dp
12use MOM_EOS, only : calculate_density
13use MOM_EOS, only : calculate_spec_vol
14use MOM_EOS, only : calculate_specific_vol_derivs
15use MOM_EOS, only : average_specific_vol
16use MOM_error_handler, only : MOM_error, FATAL, WARNING, MOM_mesg
17use MOM_hor_index, only : hor_index_type
18use MOM_string_functions, only : uppercase
19use MOM_variables, only : thermo_var_ptrs
20use MOM_unit_scaling, only : unit_scale_type
21use MOM_verticalGrid, only : verticalGrid_type
22
23implicit none ; private
24
25#include <MOM_memory.h>
26
27public int_density_dz
28public int_density_dz_generic_pcm
29public int_density_dz_generic_plm
30public int_density_dz_generic_ppm
31public int_specific_vol_dp
32public int_spec_vol_dp_generic_pcm
33public int_spec_vol_dp_generic_plm
34public avg_specific_vol
35public find_depth_of_pressure_in_cell
36public diagnose_mass_weight_Z, diagnose_mass_weight_p
37
38contains
39
40!> Calls the appropriate subroutine to calculate analytical and nearly-analytical
41!! integrals in z across layers of pressure anomalies, which are
42!! required for calculating the finite-volume form pressure accelerations in a
43!! Boussinesq model.
440subroutine int_density_dz(T, S, z_t, z_b, rho_ref, rho_0, G_e, HI, EOS, US, dpa, &
450 intz_dpa, intx_dpa, inty_dpa, bathyT, SSH, dz_neglect, MassWghtInterp, Z_0p, &
46 MassWghtInterpVanOnly, h_nv)
47 type(hor_index_type), intent(in) :: HI !< Ocean horizontal index structures for the arrays
48 real, dimension(SZI_(HI),SZJ_(HI)), &
49 intent(in) :: T !< Potential temperature referenced to the surface [C ~> degC]
50 real, dimension(SZI_(HI),SZJ_(HI)), &
51 intent(in) :: S !< Salinity [S ~> ppt]
52 real, dimension(SZI_(HI),SZJ_(HI)), &
53 intent(in) :: z_t !< Height at the top of the layer in depth units [Z ~> m]
54 real, dimension(SZI_(HI),SZJ_(HI)), &
55 intent(in) :: z_b !< Height at the bottom of the layer [Z ~> m]
56 real, intent(in) :: rho_ref !< A mean density [R ~> kg m-3], that is
57 !! subtracted out to reduce the magnitude of each of the
58 !! integrals.
59 real, intent(in) :: rho_0 !< A density [R ~> kg m-3], that is used
60 !! to calculate the pressure (as p~=-z*rho_0*G_e)
61 !! used in the equation of state.
62 real, intent(in) :: G_e !< The Earth's gravitational acceleration
63 !! [L2 Z-1 T-2 ~> m s-2]
64 type(EOS_type), intent(in) :: EOS !< Equation of state structure
65 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
66 real, dimension(SZI_(HI),SZJ_(HI)), &
67 intent(inout) :: dpa !< The change in the pressure anomaly
68 !! across the layer [R L2 T-2 ~> Pa]
69 real, dimension(SZI_(HI),SZJ_(HI)), &
70 optional, intent(inout) :: intz_dpa !< The integral through the thickness of the
71 !! layer of the pressure anomaly relative to the
72 !! anomaly at the top of the layer [R L2 Z T-2 ~> Pa m]
73 real, dimension(SZIB_(HI),SZJ_(HI)), &
74 optional, intent(inout) :: intx_dpa !< The integral in x of the difference between
75 !! the pressure anomaly at the top and bottom of the
76 !! layer divided by the x grid spacing [R L2 T-2 ~> Pa]
77 real, dimension(SZI_(HI),SZJB_(HI)), &
78 optional, intent(inout) :: inty_dpa !< The integral in y of the difference between
79 !! the pressure anomaly at the top and bottom of the
80 !! layer divided by the y grid spacing [R L2 T-2 ~> Pa]
81 real, dimension(SZI_(HI),SZJ_(HI)), &
82 optional, intent(in) :: bathyT !< The depth of the bathymetry [Z ~> m]
83 real, dimension(SZI_(HI),SZJ_(HI)), &
84 optional, intent(in) :: SSH !< The sea surface height [Z ~> m]
85 real, optional, intent(in) :: dz_neglect !< A minuscule thickness change [Z ~> m]
86 integer, optional, intent(in) :: MassWghtInterp !< A flag indicating whether and how to use
87 !! mass weighting to interpolate T/S in integrals
88 logical, optional, intent(in) :: MassWghtInterpVanOnly !< If true, does not do mass weighting
89 !! of T/S unless one side smaller than h_nv (i.e. vanished)
90 real, optional, intent(in) :: h_nv !< Nonvanished height [Z ~> m]
91
92 real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), &
93 optional, intent(in) :: Z_0p !< The height at which the pressure is 0 [Z ~> m]
94
950 if (EOS_quadrature(EOS)) then
96 call int_density_dz_generic_pcm(T, S, z_t, z_b, rho_ref, rho_0, G_e, HI, EOS, US, dpa, &
97 intz_dpa, intx_dpa, inty_dpa, bathyT, SSH, dz_neglect, &
98 MassWghtInterp, Z_0p=Z_0p, MassWghtInterpVanOnly=MassWghtInterpVanOnly, &
990 h_nv=h_nv)
100 else
101 call analytic_int_density_dz(T, S, z_t, z_b, rho_ref, rho_0, G_e, HI, EOS, dpa, &
1020 intz_dpa, intx_dpa, inty_dpa, bathyT, SSH, dz_neglect, MassWghtInterp, Z_0p=Z_0p)
103 endif
104
1050end subroutine int_density_dz
106
107
108!> Calculates (by numerical quadrature) integrals of pressure anomalies across layers, which
109!! are required for calculating the finite-volume form pressure accelerations in a Boussinesq model.
1100subroutine int_density_dz_generic_pcm(T, S, z_t, z_b, rho_ref, rho_0, G_e, HI, &
1110 EOS, US, dpa, intz_dpa, intx_dpa, inty_dpa, bathyT, SSH, &
1120 dz_neglect, MassWghtInterp, use_inaccurate_form, Z_0p, &
113 MassWghtInterpVanOnly, h_nv)
114 type(hor_index_type), intent(in) :: HI !< Horizontal index type for input variables.
115 real, dimension(SZI_(HI),SZJ_(HI)), &
116 intent(in) :: T !< Potential temperature of the layer [C ~> degC]
117 real, dimension(SZI_(HI),SZJ_(HI)), &
118 intent(in) :: S !< Salinity of the layer [S ~> ppt]
119 real, dimension(SZI_(HI),SZJ_(HI)), &
120 intent(in) :: z_t !< Height at the top of the layer in depth units [Z ~> m]
121 real, dimension(SZI_(HI),SZJ_(HI)), &
122 intent(in) :: z_b !< Height at the bottom of the layer [Z ~> m]
123 real, intent(in) :: rho_ref !< A mean density [R ~> kg m-3], that is
124 !! subtracted out to reduce the magnitude
125 !! of each of the integrals.
126 real, intent(in) :: rho_0 !< A density [R ~> kg m-3], that is used
127 !! to calculate the pressure (as p~=-z*rho_0*G_e)
128 !! used in the equation of state.
129 real, intent(in) :: G_e !< The Earth's gravitational acceleration
130 !! [L2 Z-1 T-2 ~> m s-2]
131 type(EOS_type), intent(in) :: EOS !< Equation of state structure
132 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
133 real, dimension(SZI_(HI),SZJ_(HI)), &
134 intent(inout) :: dpa !< The change in the pressure anomaly
135 !! across the layer [R L2 T-2 ~> Pa]
136 real, dimension(SZI_(HI),SZJ_(HI)), &
137 optional, intent(inout) :: intz_dpa !< The integral through the thickness of the
138 !! layer of the pressure anomaly relative to the
139 !! anomaly at the top of the layer [R L2 Z T-2 ~> Pa m]
140 real, dimension(SZIB_(HI),SZJ_(HI)), &
141 optional, intent(inout) :: intx_dpa !< The integral in x of the difference between
142 !! the pressure anomaly at the top and bottom of the
143 !! layer divided by the x grid spacing [R L2 T-2 ~> Pa]
144 real, dimension(SZI_(HI),SZJB_(HI)), &
145 optional, intent(inout) :: inty_dpa !< The integral in y of the difference between
146 !! the pressure anomaly at the top and bottom of the
147 !! layer divided by the y grid spacing [R L2 T-2 ~> Pa]
148 real, dimension(SZI_(HI),SZJ_(HI)), &
149 optional, intent(in) :: bathyT !< The depth of the bathymetry [Z ~> m]
150 real, dimension(SZI_(HI),SZJ_(HI)), &
151 optional, intent(in) :: SSH !< The sea surface height [Z ~> m]
152 real, optional, intent(in) :: dz_neglect !< A minuscule thickness change [Z ~> m]
153 integer, optional, intent(in) :: MassWghtInterp !< A flag indicating whether and how to use
154 !! mass weighting to interpolate T/S in integrals
155 logical, optional, intent(in) :: MassWghtInterpVanOnly !< If true, does not do mass weighting
156 !! of T/S unless one side smaller than h_nv (i.e. vanished)
157 real, optional, intent(in) :: h_nv !< Nonvanished height [Z ~> m]
158 logical, optional, intent(in) :: use_inaccurate_form !< If true, uses an inaccurate form of
159 !! density anomalies, as was used prior to March 2018.
160 real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), &
161 optional, intent(in) :: Z_0p !< The height at which the pressure is 0 [Z ~> m]
162
163 ! Local variables
1640 real :: T5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Temperatures along a line of subgrid locations [C ~> degC]
1650 real :: S5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Salinities along a line of subgrid locations [S ~> ppt]
1660 real :: p5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Pressures along a line of subgrid locations [R L2 T-2 ~> Pa]
1670 real :: r5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Densities anomalies along a line of subgrid locations [R ~> kg m-3]
1680 real :: T15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Temperatures at an array of subgrid locations [C ~> degC]
1690 real :: S15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Salinities at an array of subgrid locations [S ~> ppt]
1700 real :: p15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Pressures at an array of subgrid locations [R L2 T-2 ~> Pa]
1710 real :: r15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Densities at an array of subgrid locations [R ~> kg m-3]
172 real :: rho_anom ! The depth averaged density anomaly [R ~> kg m-3]
173 real, parameter :: C1_90 = 1.0/90.0 ! A rational constant [nondim]
174 real :: GxRho ! The product of the gravitational acceleration and reference density [R L2 Z-1 T-2 ~> Pa m-1]
175 real :: dz ! The layer thickness [Z ~> m]
1760 real :: dz_x(5,HI%iscB:HI%iecB) ! Layer thicknesses along an x-line of subgrid locations [Z ~> m]
1770 real :: dz_y(5,HI%isc:HI%iec) ! Layer thicknesses along a y-line of subgrid locations [Z ~> m]
1780 real :: z0pres(HI%isd:HI%ied,HI%jsd:HI%jed) ! The height at which the pressure is zero [Z ~> m]
179 real :: hWght ! A pressure-thickness below topography [Z ~> m]
180 real :: hL, hR ! Pressure-thicknesses of the columns to the left and right [Z ~> m]
181 real :: iDenom ! The inverse of the denominator in the weights [Z-2 ~> m-2]
182 real :: hWt_LL, hWt_LR ! hWt_LA is the weighted influence of A on the left column [nondim]
183 real :: hWt_RL, hWt_RR ! hWt_RA is the weighted influence of A on the right column [nondim]
184 real :: wt_L, wt_R ! The linear weights of the left and right columns [nondim]
185 real :: wtT_L, wtT_R ! The weights for tracers from the left and right columns [nondim]
186 real :: intz(5) ! The gravitational acceleration times the integrals of density
187 ! with height at the 5 sub-column locations [R L2 T-2 ~> Pa]
188 logical :: do_massWeight ! Indicates whether to do mass weighting near bathymetry
189 logical :: top_massWeight ! Indicates whether to do mass weighting the sea surface
190 real :: massWeightNVonlyToggle ! A non-dimensional toggle factor for only using mass weighting
191 ! if at least one side vanished (0 or 1) [nondim]
192 real :: h_nonvanished ! nonvanished height [Z ~> m]
193 logical :: use_rho_ref ! Pass rho_ref to the equation of state for more accurate calculation
194 ! of density anomalies.
195 integer, dimension(2) :: EOSdom_h5 ! The 5-point h-point i-computational domain for the equation of state
196 integer, dimension(2) :: EOSdom_q15 ! The 3x5-point q-point i-computational domain for the equation of state
197 integer, dimension(2) :: EOSdom_h15 ! The 3x5-point h-point i-computational domain for the equation of state
198 integer :: is, ie, js, je, Isq, Ieq, Jsq, Jeq, i, j, m, n, pos
199
200 ! These array bounds work for the indexing convention of the input arrays, but
201 ! on the computational domain defined for the output arrays.
2020 Isq = HI%IscB ; Ieq = HI%IecB
2030 Jsq = HI%JscB ; Jeq = HI%JecB
2040 is = HI%isc ; ie = HI%iec
2050 js = HI%jsc ; je = HI%jec
206
2070 GxRho = G_e * rho_0
2080 if (present(Z_0p)) then
2090 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
2100 z0pres(i,j) = Z_0p(i,j)
211 enddo ; enddo
212 else
2130 z0pres(:,:) = 0.0
214 endif
2150 use_rho_ref = .true.
2160 if (present(use_inaccurate_form)) then
2170 if (use_inaccurate_form) use_rho_ref = .not. use_inaccurate_form
218 endif
219
2200 do_massWeight = .false. ; top_massWeight = .false.
2210 if (present(MassWghtInterp)) then
2220 do_massWeight = BTEST(MassWghtInterp, 0) ! True for odd values
2230 top_massWeight = BTEST(MassWghtInterp, 1) ! True if the 2 bit is set
2240 if (do_massWeight .and. .not.present(bathyT)) call MOM_error(FATAL, &
2250 "int_density_dz_generic: bathyT must be present if near-bottom mass weighting is in use.")
2260 if (top_massWeight .and. .not.present(SSH)) call MOM_error(FATAL, &
2270 "int_density_dz_generic: SSH must be present if near-surface mass weighting is in use.")
2280 if ((do_massWeight .or. top_massWeight) .and. .not.present(dz_neglect)) call MOM_error(FATAL, &
2290 "int_density_dz_generic: dz_neglect must be present if mass weighting is in use.")
230 endif
2310 massWeightNVonlyToggle = 1.
2320 if (present(MassWghtInterpVanOnly)) then
2330 if (MassWghtInterpVanOnly) massWeightNVonlyToggle = 0.
234 endif
2350 h_nonvanished = 0.
2360 if (present(h_nv)) then
2370 h_nonvanished = h_nv
238 endif
239
240 ! Set the loop ranges for equation of state calculations at various points.
2410 EOSdom_h5(1) = 1 ; EOSdom_h5(2) = 5*(Ieq-Isq+2)
2420 EOSdom_q15(1) = 1 ; EOSdom_q15(2) = 15*(Ieq-Isq+1)
2430 EOSdom_h15(1) = 1 ; EOSdom_h15(2) = 15*(HI%iec-HI%isc+1)
244
2450 do j=Jsq,Jeq+1
2460 do i=Isq,Ieq+1
2470 dz = z_t(i,j) - z_b(i,j)
2480 do n=1,5
2490 T5(i*5+n) = T(i,j) ; S5(i*5+n) = S(i,j)
2500 p5(i*5+n) = -GxRho*((z_t(i,j) - z0pres(i,j)) - 0.25*real(n-1)*dz)
251 enddo
252 enddo
253
2540 if (use_rho_ref) then
2550 call calculate_density(T5, S5, p5, r5, EOS, EOSdom_h5, rho_ref=rho_ref)
256 else
2570 call calculate_density(T5, S5, p5, r5, EOS, EOSdom_h5)
258 endif
259
2600 do i=Isq,Ieq+1
261 ! Use Boole's rule to estimate the pressure anomaly change.
2620 rho_anom = C1_90*(7.0*(r5(i*5+1)+r5(i*5+5)) + 32.0*(r5(i*5+2)+r5(i*5+4)) + 12.0*r5(i*5+3))
2630 if (.not.use_rho_ref) rho_anom = rho_anom - rho_ref
2640 dz = z_t(i,j) - z_b(i,j)
2650 dpa(i,j) = G_e*dz*rho_anom
266 ! Use a Boole's-rule-like fifth-order accurate estimate of the double integral of
267 ! the pressure anomaly.
2680 if (present(intz_dpa)) intz_dpa(i,j) = 0.5*G_e*dz**2 * &
2690 (rho_anom - C1_90*(16.0*(r5(i*5+4)-r5(i*5+2)) + 7.0*(r5(i*5+5)-r5(i*5+1))) )
270 enddo
271 enddo
272
2730 if (present(intx_dpa)) then ; do j=js,je
2740 do I=Isq,Ieq
275 ! hWght is the distance measure by which the cell is violation of
276 ! hydrostatic consistency. For large hWght we bias the interpolation of
277 ! T & S along the top and bottom integrals, akin to thickness weighting.
2780 hWght = 0.0
2790 if (do_massWeight) &
2800 hWght = max(0., -bathyT(i,j)-z_t(i+1,j), -bathyT(i+1,j)-z_t(i,j))
2810 if (top_massWeight) &
2820 hWght = max(hWght, z_b(i+1,j)-SSH(i,j), z_b(i,j)-SSH(i+1,j))
283 ! If both sides are nonvanished, then set it back to zero.
2840 if (((z_t(i,j) - z_b(i,j)) > h_nonvanished) .and. ((z_t(i+1,j) - z_b(i+1,j)) > h_nonvanished)) then
2850 hWght = massWeightNVonlyToggle * hWght
286 endif
2870 if (hWght > 0.) then
2880 hL = (z_t(i,j) - z_b(i,j)) + dz_neglect
2890 hR = (z_t(i+1,j) - z_b(i+1,j)) + dz_neglect
2900 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
2910 iDenom = 1.0 / ( hWght*(hR + hL) + hL*hR )
2920 hWt_LL = (hWght*hL + hR*hL) * iDenom ; hWt_LR = (hWght*hR) * iDenom
2930 hWt_RR = (hWght*hR + hR*hL) * iDenom ; hWt_RL = (hWght*hL) * iDenom
294 else
2950 hWt_LL = 1.0 ; hWt_LR = 0.0 ; hWt_RR = 1.0 ; hWt_RL = 0.0
296 endif
297
2980 do m=2,4
299 ! T, S, and z are interpolated in the horizontal. The z interpolation
300 ! is linear, but for T and S it may be thickness weighted.
3010 wt_L = 0.25*real(5-m) ; wt_R = 1.0-wt_L
3020 wtT_L = (wt_L*hWt_LL) + (wt_R*hWt_RL) ; wtT_R = (wt_L*hWt_LR) + (wt_R*hWt_RR)
3030 dz_x(m,i) = (wt_L*(z_t(i,j) - z_b(i,j))) + (wt_R*(z_t(i+1,j) - z_b(i+1,j)))
3040 pos = i*15+(m-2)*5
3050 T15(pos+1) = (wtT_L*T(i,j)) + (wtT_R*T(i+1,j))
3060 S15(pos+1) = (wtT_L*S(i,j)) + (wtT_R*S(i+1,j))
3070 p15(pos+1) = -GxRho * ((wt_L*(z_t(i,j)-z0pres(i,j))) + (wt_R*(z_t(i+1,j)-z0pres(i+1,j))))
3080 do n=2,5
3090 T15(pos+n) = T15(pos+1) ; S15(pos+n) = S15(pos+1)
3100 p15(pos+n) = p15(pos+n-1) + GxRho*0.25*dz_x(m,i)
311 enddo
312 enddo
313 enddo
314
3150 if (use_rho_ref) then
3160 call calculate_density(T15, S15, p15, r15, EOS, EOSdom_q15, rho_ref=rho_ref)
317 else
3180 call calculate_density(T15, S15, p15, r15, EOS, EOSdom_q15)
319 endif
320
3210 do I=Isq,Ieq
3220 intz(1) = dpa(i,j) ; intz(5) = dpa(i+1,j)
323 ! Use Boole's rule to estimate the pressure anomaly change.
3240 if (use_rho_ref) then
3250 do m=2,4
3260 pos = i*15+(m-2)*5
327 intz(m) = (G_e*dz_x(m,i)*(C1_90*( 7.0*(r15(pos+1)+r15(pos+5)) + &
328 32.0*(r15(pos+2)+r15(pos+4)) + &
3290 12.0*r15(pos+3)) ))
330 enddo
331 else
3320 do m=2,4
3330 pos = i*15+(m-2)*5
334 intz(m) = (G_e*dz_x(m,i)*(C1_90*( 7.0*(r15(pos+1)+r15(pos+5)) + &
335 32.0*(r15(pos+2)+r15(pos+4)) + &
3360 12.0*r15(pos+3)) - rho_ref ))
337 enddo
338 endif
339 ! Use Boole's rule to integrate the bottom pressure anomaly values in x.
340 intx_dpa(i,j) = C1_90*(7.0*(intz(1)+intz(5)) + 32.0*(intz(2)+intz(4)) + &
3410 12.0*intz(3))
342 enddo
343 enddo ; endif
344
3450 if (present(inty_dpa)) then ; do J=Jsq,Jeq
3460 do i=is,ie
347 ! hWght is the distance measure by which the cell is violation of
348 ! hydrostatic consistency. For large hWght we bias the interpolation of
349 ! T & S along the top and bottom integrals, akin to thickness weighting.
3500 hWght = 0.0
3510 if (do_massWeight) &
3520 hWght = max(0., -bathyT(i,j)-z_t(i,j+1), -bathyT(i,j+1)-z_t(i,j))
3530 if (top_massWeight) &
3540 hWght = max(hWght, z_b(i,j+1)-SSH(i,j), z_b(i,j)-SSH(i,j+1))
355 ! If both sides are nonvanished, then set it back to zero.
3560 if (((z_t(i,j) - z_b(i,j)) > h_nonvanished) .and. ((z_t(i,j+1) - z_b(i,j+1)) > h_nonvanished)) then
3570 hWght = massWeightNVonlyToggle * hWght
358 endif
3590 if (hWght > 0.) then
3600 hL = (z_t(i,j) - z_b(i,j)) + dz_neglect
3610 hR = (z_t(i,j+1) - z_b(i,j+1)) + dz_neglect
3620 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
3630 iDenom = 1.0 / ( hWght*(hR + hL) + hL*hR )
3640 hWt_LL = (hWght*hL + hR*hL) * iDenom ; hWt_LR = (hWght*hR) * iDenom
3650 hWt_RR = (hWght*hR + hR*hL) * iDenom ; hWt_RL = (hWght*hL) * iDenom
366 else
3670 hWt_LL = 1.0 ; hWt_LR = 0.0 ; hWt_RR = 1.0 ; hWt_RL = 0.0
368 endif
369
3700 do m=2,4
371 ! T, S, and z are interpolated in the horizontal. The z interpolation
372 ! is linear, but for T and S it may be thickness weighted.
3730 wt_L = 0.25*real(5-m) ; wt_R = 1.0-wt_L
3740 wtT_L = (wt_L*hWt_LL) + (wt_R*hWt_RL) ; wtT_R = (wt_L*hWt_LR) + (wt_R*hWt_RR)
3750 dz_y(m,i) = (wt_L*(z_t(i,j) - z_b(i,j))) + (wt_R*(z_t(i,j+1) - z_b(i,j+1)))
3760 pos = i*15+(m-2)*5
3770 T15(pos+1) = (wtT_L*T(i,j)) + (wtT_R*T(i,j+1))
3780 S15(pos+1) = (wtT_L*S(i,j)) + (wtT_R*S(i,j+1))
3790 p15(pos+1) = -GxRho * ((wt_L*(z_t(i,j)-z0pres(i,j))) + (wt_R*(z_t(i,j+1)-z0pres(i,j+1))))
3800 do n=2,5
3810 T15(pos+n) = T15(pos+1) ; S15(pos+n) = S15(pos+1)
3820 p15(pos+n) = p15(pos+n-1) + GxRho*0.25*dz_y(m,i)
383 enddo
384 enddo
385 enddo
386
3870 if (use_rho_ref) then
388 call calculate_density(T15(15*HI%isc+1:), S15(15*HI%isc+1:), p15(15*HI%isc+1:), &
3890 r15(15*HI%isc+1:), EOS, EOSdom_h15, rho_ref=rho_ref)
390 else
391 call calculate_density(T15(15*HI%isc+1:), S15(15*HI%isc+1:), p15(15*HI%isc+1:), &
3920 r15(15*HI%isc+1:), EOS, EOSdom_h15)
393 endif
394
3950 do i=is,ie
3960 intz(1) = dpa(i,j) ; intz(5) = dpa(i,j+1)
397 ! Use Boole's rule to estimate the pressure anomaly change.
3980 do m=2,4
3990 pos = i*15+(m-2)*5
4000 if (use_rho_ref) then
401 intz(m) = (G_e*dz_y(m,i)*(C1_90*(7.0*(r15(pos+1)+r15(pos+5)) + &
402 32.0*(r15(pos+2)+r15(pos+4)) + &
4030 12.0*r15(pos+3)) ))
404 else
405 intz(m) = (G_e*dz_y(m,i)*(C1_90*(7.0*(r15(pos+1)+r15(pos+5)) + &
406 32.0*(r15(pos+2)+r15(pos+4)) + &
4070 12.0*r15(pos+3)) - rho_ref ))
408 endif
409 enddo
410 ! Use Boole's rule to integrate the values.
411 inty_dpa(i,j) = C1_90*(7.0*(intz(1)+intz(5)) + 32.0*(intz(2)+intz(4)) + &
4120 12.0*intz(3))
413 enddo
414 enddo ; endif
4150end subroutine int_density_dz_generic_pcm
416
417
418!> Compute pressure gradient force integrals by quadrature for the case where
419!! T and S are linear profiles.
4203600subroutine int_density_dz_generic_plm(k, tv, T_t, T_b, S_t, S_b, e, rho_ref, &
4213600 rho_0, G_e, dz_subroundoff, bathyT, HI, GV, EOS, US, use_stanley_eos, dpa, &
4225400 intz_dpa, intx_dpa, inty_dpa, MassWghtInterp, &
4231800 use_inaccurate_form, Z_0p, MassWghtInterpVanOnly, h_nv)
424 integer, intent(in) :: k !< Layer index to calculate integrals for
425 type(hor_index_type), intent(in) :: HI !< Ocean horizontal index structures for the input arrays
426 type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure
427 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamic variables
428 real, dimension(SZI_(HI),SZJ_(HI),SZK_(GV)), &
429 intent(in) :: T_t !< Potential temperature at the cell top [C ~> degC]
430 real, dimension(SZI_(HI),SZJ_(HI),SZK_(GV)), &
431 intent(in) :: T_b !< Potential temperature at the cell bottom [C ~> degC]
432 real, dimension(SZI_(HI),SZJ_(HI),SZK_(GV)), &
433 intent(in) :: S_t !< Salinity at the cell top [S ~> ppt]
434 real, dimension(SZI_(HI),SZJ_(HI),SZK_(GV)), &
435 intent(in) :: S_b !< Salinity at the cell bottom [S ~> ppt]
436 real, dimension(SZI_(HI),SZJ_(HI),SZK_(GV)+1), &
437 intent(in) :: e !< Height of interfaces [Z ~> m]
438 real, intent(in) :: rho_ref !< A mean density [R ~> kg m-3], that is subtracted
439 !! out to reduce the magnitude of each of the integrals.
440 real, intent(in) :: rho_0 !< A density [R ~> kg m-3], that is used to calculate
441 !! the pressure (as p~=-z*rho_0*G_e) used in the equation of state.
442 real, intent(in) :: G_e !< The Earth's gravitational acceleration [L2 Z-1 T-2 ~> m s-2]
443 real, intent(in) :: dz_subroundoff !< A minuscule thickness change [Z ~> m]
444 real, dimension(SZI_(HI),SZJ_(HI)), &
445 intent(in) :: bathyT !< The depth of the bathymetry [Z ~> m]
446 type(EOS_type), intent(in) :: EOS !< Equation of state structure
447 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
448 logical, intent(in) :: use_stanley_eos !< If true, turn on Stanley SGS T variance parameterization
449 real, dimension(SZI_(HI),SZJ_(HI)), &
450 intent(inout) :: dpa !< The change in the pressure anomaly across the layer [R L2 T-2 ~> Pa]
451 real, dimension(SZI_(HI),SZJ_(HI)), &
452 optional, intent(inout) :: intz_dpa !< The integral through the thickness of the layer of
453 !! the pressure anomaly relative to the anomaly at the
454 !! top of the layer [R L2 Z T-2 ~> Pa m]
455 real, dimension(SZIB_(HI),SZJ_(HI)), &
456 optional, intent(inout) :: intx_dpa !< The integral in x of the difference between the
457 !! pressure anomaly at the top and bottom of the layer
458 !! divided by the x grid spacing [R L2 T-2 ~> Pa]
459 real, dimension(SZI_(HI),SZJB_(HI)), &
460 optional, intent(inout) :: inty_dpa !< The integral in y of the difference between the
461 !! pressure anomaly at the top and bottom of the layer
462 !! divided by the y grid spacing [R L2 T-2 ~> Pa]
463 integer, optional, intent(in) :: MassWghtInterp !< A flag indicating whether and how to use
464 !! mass weighting to interpolate T/S in integrals
465 logical, optional, intent(in) :: use_inaccurate_form !< If true, uses an inaccurate form of
466 !! density anomalies, as was used prior to March 2018.
467 logical, optional, intent(in) :: MassWghtInterpVanOnly !< If true, does not do mass weighting
468 !! of T/S unless one side smaller than h_nv (i.e. vanished)
469 real, optional, intent(in) :: h_nv !< Nonvanished height [Z ~> m]
470 real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), &
471 optional, intent(in) :: Z_0p !< The height at which the pressure is 0 [Z ~> m]
472
473! This subroutine calculates (by numerical quadrature) integrals of
474! pressure anomalies across layers, which are required for calculating the
475! finite-volume form pressure accelerations in a Boussinesq model. The one
476! potentially dodgy assumption here is that rho_0 is used both in the denominator
477! of the accelerations, and in the pressure used to calculated density (the
478! latter being -z*rho_0*G_e). These two uses could be separated if need be.
479!
480! It is assumed that the salinity and temperature profiles are linear in the
481! vertical. The top and bottom values within each layer are provided and
482! a linear interpolation is used to compute intermediate values.
483
484 ! Local variables
4853600 real :: T5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Temperatures along a line of subgrid locations [C ~> degC]
4863600 real :: S5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Salinities along a line of subgrid locations [S ~> ppt]
4873600 real :: T25((5*HI%iscB+1):(5*(HI%iecB+2))) ! SGS temperature variance along a line of subgrid
488 ! locations [C2 ~> degC2]
4893600 real :: TS5((5*HI%iscB+1):(5*(HI%iecB+2))) ! SGS temp-salt covariance along a line of subgrid
490 ! locations [C S ~> degC ppt]
4913600 real :: S25((5*HI%iscB+1):(5*(HI%iecB+2))) ! SGS salinity variance along a line of subgrid locations [S2 ~> ppt2]
4923600 real :: p5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Pressures along a line of subgrid locations [R L2 T-2 ~> Pa]
4933600 real :: r5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Densities anomalies along a line of subgrid
494 ! locations [R ~> kg m-3]
4953600 real :: u5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Densities anomalies along a line of subgrid locations
496 ! (used for inaccurate form) [R ~> kg m-3]
4973600 real :: T15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Temperatures at an array of subgrid locations [C ~> degC]
4983600 real :: S15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Salinities at an array of subgrid locations [S ~> ppt]
4993600 real :: T215((15*HI%iscB+1):(15*(HI%iecB+1))) ! SGS temperature variance along a line of subgrid
500 ! locations [C2 ~> degC2]
5013600 real :: TS15((15*HI%iscB+1):(15*(HI%iecB+1))) ! SGS temp-salt covariance along a line of subgrid
502 ! locations [C S ~> degC ppt]
5033600 real :: S215((15*HI%iscB+1):(15*(HI%iecB+1))) ! SGS salinity variance along a line of subgrid
504 ! locations [S2 ~> ppt2]
5053600 real :: p15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Pressures at an array of subgrid locations [R L2 T-2 ~> Pa]
5063600 real :: r15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Densities at an array of subgrid locations [R ~> kg m-3]
507 real :: wt_t(5), wt_b(5) ! Top and bottom weights [nondim]
508 real :: rho_anom ! A density anomaly [R ~> kg m-3]
509 real :: w_left, w_right ! Left and right weights [nondim]
510 real :: intz(5) ! The gravitational acceleration times the integrals of density
511 ! with height at the 5 sub-column locations [R L2 T-2 ~> Pa]
512 real, parameter :: C1_90 = 1.0/90.0 ! A rational constant [nondim]
513 real :: GxRho ! The product of the gravitational acceleration and reference density [R L2 Z-1 T-2 ~> Pa m-1]
5143600 real :: dz(HI%iscB:HI%iecB+1) ! Layer thicknesses at tracer points [Z ~> m]
5153600 real :: dz_x(5,HI%iscB:HI%iecB) ! Layer thicknesses along an x-line of subgrid locations [Z ~> m]
5163600 real :: dz_y(5,HI%isc:HI%iec) ! Layer thicknesses along a y-line of subgrid locations [Z ~> m]
517 real :: massWeightToggle ! A non-dimensional toggle factor for near-bottom mass weighting (0 or 1) [nondim]
518 real :: TopWeightToggle ! A non-dimensional toggle factor for near-surface mass weighting (0 or 1) [nondim]
519 real :: massWeightNVonlyToggle ! A non-dimensional toggle factor for only using mass weighting
520 ! if at least one side vanished (0 or 1) [nondim]
521 real :: Ttl, Tbl, Ttr, Tbr ! Temperatures at the velocity cell corners [C ~> degC]
522 real :: Stl, Sbl, Str, Sbr ! Salinities at the velocity cell corners [S ~> ppt]
5233600 real :: z0pres(HI%isd:HI%ied,HI%jsd:HI%jed) ! The height at which the pressure is zero [Z ~> m]
524 real :: hWght ! A topographically limited thickness weight [Z ~> m]
525 real :: hWghtTop ! An ice draft limited thickness weight [Z ~> m]
526 real :: hL, hR ! Thicknesses to the left and right [Z ~> m]
527 real :: iDenom ! The denominator of the thickness weight expressions [Z-2 ~> m-2]
528 real :: h_nonvanished ! nonvanished height [Z ~> m]
529 logical :: use_rho_ref ! Pass rho_ref to the equation of state for more accurate calculation
530 ! of density anomalies.
531 logical :: use_varT, use_varS, use_covarTS ! Logicals for SGS variances fields
532 integer, dimension(2) :: EOSdom_h5 ! The 5-point h-point i-computational domain for the equation of state
533 integer, dimension(2) :: EOSdom_q15 ! The 3x5-point q-point i-computational domain for the equation of state
534 integer, dimension(2) :: EOSdom_h15 ! The 3x5-point h-point i-computational domain for the equation of state
535 integer :: Isq, Ieq, Jsq, Jeq, i, j, m, n, pos
536
5371800 Isq = HI%IscB ; Ieq = HI%IecB ; Jsq = HI%JscB ; Jeq = HI%JecB
538
5391800 GxRho = G_e * rho_0
5401800 if (present(Z_0p)) then
54113728600 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
54213726800 z0pres(i,j) = Z_0p(i,j)
543 enddo ; enddo
544 else
5450 z0pres(:,:) = 0.0
546 endif
5471800 massWeightToggle = 0. ; TopWeightToggle = 0.
5481800 if (present(MassWghtInterp)) then
5491800 if (BTEST(MassWghtInterp, 0)) massWeightToggle = 1.
5501800 if (BTEST(MassWghtInterp, 1)) TopWeightToggle = 1.
551 endif
5521800 massWeightNVonlyToggle = 1.
5531800 if (present(MassWghtInterpVanOnly)) then
5541800 if (MassWghtInterpVanOnly) massWeightNVonlyToggle = 0.
555 endif
5561800 h_nonvanished = 0.
5571800 if (present(h_nv)) then
5581800 h_nonvanished = h_nv
559 endif
5601800 use_rho_ref = .true.
5611800 if (present(use_inaccurate_form)) use_rho_ref = .not. use_inaccurate_form
562
5631800 use_varT = .false. !ensure initialized
5641800 use_covarTS = .false.
5651800 use_varS = .false.
5661800 if (use_stanley_eos) then
5670 use_varT = associated(tv%varT)
5680 use_covarTS = associated(tv%covarTS)
5690 use_varS = associated(tv%varS)
570 endif
571
5721099800 T25(:) = 0.
5731099800 TS5(:) = 0.
5741099800 S25(:) = 0.
5753268800 T215(:) = 0.
5763268800 TS15(:) = 0.
5773268800 S215(:) = 0.
578
57910800 do n = 1, 5
5809000 wt_t(n) = 0.25 * real(5-n)
58110800 wt_b(n) = 1.0 - wt_t(n)
582 enddo
583
584 ! Set the loop ranges for equation of state calculations at various points.
5851800 EOSdom_h5(1) = 1 ; EOSdom_h5(2) = 5*(Ieq-Isq+2)
5861800 EOSdom_q15(1) = 1 ; EOSdom_q15(2) = 15*(Ieq-Isq+1)
5871800 EOSdom_h15(1) = 1 ; EOSdom_h15(2) = 15*(HI%iec-HI%isc+1)
588
589 ! 1. Compute vertical integrals
590113400 do j=Jsq,Jeq+1
59113726800 do i = Isq,Ieq+1
59213615200 dz(i) = e(i,j,K) - e(i,j,K+1)
59381691200 do n=1,5
59468076000 p5(i*5+n) = -GxRho*((e(i,j,K) - z0pres(i,j)) - 0.25*real(n-1)*dz(i))
595 ! Salinity and temperature points are linearly interpolated
59668076000 S5(i*5+n) = wt_t(n) * S_t(i,j,k) + wt_b(n) * S_b(i,j,k)
59781691200 T5(i*5+n) = wt_t(n) * T_t(i,j,k) + wt_b(n) * T_b(i,j,k)
598 enddo
59913615200 if (use_varT) T25(i*5+1:i*5+5) = tv%varT(i,j,k)
60013615200 if (use_covarTS) TS5(i*5+1:i*5+5) = tv%covarTS(i,j,k)
60113726800 if (use_varS) S25(i*5+1:i*5+5) = tv%varS(i,j,k)
602 enddo
603111600 if (use_Stanley_eos) then
6040 call calculate_density(T5, S5, p5, T25, TS5, S25, r5, EOS, EOSdom_h5, rho_ref=rho_ref)
605 else
606111600 if (use_rho_ref) then
607111600 call calculate_density(T5, S5, p5, r5, EOS, EOSdom_h5, rho_ref=rho_ref)
608 else
6090 call calculate_density(T5, S5, p5, r5, EOS, EOSdom_h5)
6100 u5(:) = r5(:) - rho_ref
611 endif
612 endif
613
614113400 if (use_rho_ref) then
61513726800 do i=Isq,Ieq+1
616 ! Use Boole's rule to estimate the pressure anomaly change.
61713615200 rho_anom = C1_90*(7.0*(r5(i*5+1)+r5(i*5+5)) + 32.0*(r5(i*5+2)+r5(i*5+4)) + 12.0*r5(i*5+3))
61813615200 dpa(i,j) = G_e*dz(i)*rho_anom
61913726800 if (present(intz_dpa)) then
620 ! Use a Boole's-rule-like fifth-order accurate estimate of
621 ! the double integral of the pressure anomaly.
622 intz_dpa(i,j) = 0.5*G_e*dz(i)**2 * &
62313615200 (rho_anom - C1_90*(16.0*(r5(i*5+4)-r5(i*5+2)) + 7.0*(r5(i*5+5)-r5(i*5+1))) )
624 endif
625 enddo
626 else
6270 do i=Isq,Ieq+1
628 ! Use Boole's rule to estimate the pressure anomaly change.
629 rho_anom = C1_90*(7.0*(r5(i*5+1)+r5(i*5+5)) + 32.0*(r5(i*5+2)+r5(i*5+4)) + 12.0*r5(i*5+3)) &
6300 - rho_ref
6310 dpa(i,j) = G_e*dz(i)*rho_anom
6320 if (present(intz_dpa)) then
633 ! Use a Boole's-rule-like fifth-order accurate estimate of
634 ! the double integral of the pressure anomaly.
635 intz_dpa(i,j) = 0.5*G_e*dz(i)**2 * &
6360 (rho_anom - C1_90*(16.0*(u5(i*5+4)-u5(i*5+2)) + 7.0*(u5(i*5+5)-u5(i*5+1))) )
637 endif
638 enddo
639 endif
640 enddo ! end loops on j
641
642 ! 2. Compute horizontal integrals in the x direction
643109800 if (present(intx_dpa)) then ; do j=HI%jsc,HI%jec
64413176000 do I=Isq,Ieq
645 ! Corner values of T and S
646 ! hWght is the distance measure by which the cell is violation of
647 ! hydrostatic consistency. For large hWght we bias the interpolation
648 ! of T,S along the top and bottom integrals, almost like thickness
649 ! weighting.
650 ! Note: To work in terrain following coordinates we could offset
651 ! this distance by the layer thickness to replicate other models.
652 hWght = massWeightToggle * &
65313068000 max(0., -bathyT(i,j)-e(i+1,j,K), -bathyT(i+1,j)-e(i,j,K))
654 ! CY: The below code just uses top interface, which may be bad in high res open ocean
655 ! We want something like if (pa(i+1,k+1)<pa(i,1)) or (pa(i+1,1) <pa(i,k+1)) then...
656 ! but pressures are not passed through to this submodule, and tv just has surface press.
657 !if ((p(i+1,j,k+1)<p(i,j,1)).or.(tv%p(i+1,j,k+1)<tv%p(i,j,1))) then
658 hWghtTop = TopWeightToggle * &
65913068000 max(0., e(i+1,j,K+1)-e(i,j,1), e(i,j,K+1)-e(i+1,j,1))
660 !else ! pressure criteria not activated
661 ! hWghtTop = 0.
662 !endif
663 ! Set it to be max of the bottom and top hWghts:
66413068000 hWght = max(hWght, hWghtTop)
665 ! If both sides are nonvanished, then set it back to zero.
66613068000 if (((e(i,j,K) - e(i,j,K+1)) > h_nonvanished) .and. ((e(i+1,j,K) - e(i+1,j,K+1)) > h_nonvanished)) then
66713068000 hWght = massWeightNVonlyToggle * hWght
668 endif
66913068000 if (hWght > 0.) then
6703069590 hL = (e(i,j,K) - e(i,j,K+1)) + dz_subroundoff
6713069590 hR = (e(i+1,j,K) - e(i+1,j,K+1)) + dz_subroundoff
6723069590 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
6733069590 iDenom = 1./( hWght*(hR + hL) + hL*hR )
6743069590 Ttl = ( (hWght*hR)*T_t(i+1,j,k) + (hWght*hL + hR*hL)*T_t(i,j,k) ) * iDenom
6753069590 Ttr = ( (hWght*hL)*T_t(i,j,k) + (hWght*hR + hR*hL)*T_t(i+1,j,k) ) * iDenom
6763069590 Tbl = ( (hWght*hR)*T_b(i+1,j,k) + (hWght*hL + hR*hL)*T_b(i,j,k) ) * iDenom
6773069590 Tbr = ( (hWght*hL)*T_b(i,j,k) + (hWght*hR + hR*hL)*T_b(i+1,j,k) ) * iDenom
6783069590 Stl = ( (hWght*hR)*S_t(i+1,j,k) + (hWght*hL + hR*hL)*S_t(i,j,k) ) * iDenom
6793069590 Str = ( (hWght*hL)*S_t(i,j,k) + (hWght*hR + hR*hL)*S_t(i+1,j,k) ) * iDenom
6803069590 Sbl = ( (hWght*hR)*S_b(i+1,j,k) + (hWght*hL + hR*hL)*S_b(i,j,k) ) * iDenom
6813069590 Sbr = ( (hWght*hL)*S_b(i,j,k) + (hWght*hR + hR*hL)*S_b(i+1,j,k) ) * iDenom
682 else
6839998410 Ttl = T_t(i,j,k) ; Tbl = T_b(i,j,k) ; Ttr = T_t(i+1,j,k) ; Tbr = T_b(i+1,j,k)
6849998410 Stl = S_t(i,j,k) ; Sbl = S_b(i,j,k) ; Str = S_t(i+1,j,k) ; Sbr = S_b(i+1,j,k)
685 endif
686
68752380000 do m=2,4
68839204000 w_left = wt_t(m) ; w_right = wt_b(m)
68939204000 dz_x(m,i) = (w_left*(e(i,j,K) - e(i,j,K+1))) + (w_right*(e(i+1,j,K) - e(i+1,j,K+1)))
690
691 ! Salinity and temperature points are linearly interpolated in
692 ! the horizontal. The subscript (1) refers to the top value in
693 ! the vertical profile while subscript (5) refers to the bottom
694 ! value in the vertical profile.
69539204000 pos = i*15+(m-2)*5
69639204000 T15(pos+1) = (w_left*Ttl) + (w_right*Ttr)
69739204000 T15(pos+5) = (w_left*Tbl) + (w_right*Tbr)
698
69939204000 S15(pos+1) = (w_left*Stl) + (w_right*Str)
70039204000 S15(pos+5) = (w_left*Sbl) + (w_right*Sbr)
701
70239204000 p15(pos+1) = -GxRho * ((w_left*(e(i,j,K)-z0pres(i,j))) + (w_right*(e(i+1,j,K)-z0pres(i+1,j))))
703
704 ! Pressure
705196020000 do n=2,5
706196020000 p15(pos+n) = p15(pos+n-1) + GxRho*0.25*dz_x(m,i)
707 enddo
708
709 ! Salinity and temperature (linear interpolation in the vertical)
710156816000 do n=2,4
711117612000 S15(pos+n) = wt_t(n) * S15(pos+1) + wt_b(n) * S15(pos+5)
712156816000 T15(pos+n) = wt_t(n) * T15(pos+1) + wt_b(n) * T15(pos+5)
713 enddo
71439204000 if (use_varT) T215(pos+1:pos+5) = (w_left*tv%varT(i,j,k)) + (w_right*tv%varT(i+1,j,k))
71539204000 if (use_covarTS) TS15(pos+1:pos+5) = (w_left*tv%covarTS(i,j,k)) + (w_right*tv%covarTS(i+1,j,k))
71652272000 if (use_varS) S215(pos+1:pos+5) = (w_left*tv%varS(i,j,k)) + (w_right*tv%varS(i+1,j,k))
717 enddo
718 enddo
719
720108000 if (use_stanley_eos) then
7210 call calculate_density(T15, S15, p15, T215, TS15, S215, r15, EOS, EOSdom_q15, rho_ref=rho_ref)
722 else
723108000 if (use_rho_ref) then
724108000 call calculate_density(T15, S15, p15, r15, EOS, EOSdom_q15, rho_ref=rho_ref)
725 else
7260 call calculate_density(T15, S15, p15, r15, EOS, EOSdom_q15)
727 endif
728 endif
729
73013177800 do I=Isq,Ieq
73113068000 intz(1) = dpa(i,j) ; intz(5) = dpa(i+1,j)
732
733 ! Use Boole's rule to estimate the pressure anomaly change.
73413068000 if (use_rho_ref) then
73552272000 do m = 2,4
73639204000 pos = i*15+(m-2)*5
737 intz(m) = (G_e*dz_x(m,i)*( C1_90*(7.0*(r15(pos+1)+r15(pos+5)) + 32.0*(r15(pos+2)+r15(pos+4)) + &
73852272000 12.0*r15(pos+3)) ))
739 enddo
740 else
7410 do m = 2,4
7420 pos = i*15+(m-2)*5
743 intz(m) = (G_e*dz_x(m,i)*( C1_90*(7.0*(r15(pos+1)+r15(pos+5)) + 32.0*(r15(pos+2)+r15(pos+4)) + &
7440 12.0*r15(pos+3)) - rho_ref ))
745 enddo
746 endif
747 ! Use Boole's rule to integrate the bottom pressure anomaly values in x.
748 intx_dpa(I,j) = C1_90*(7.0*(intz(1)+intz(5)) + 32.0*(intz(2)+intz(4)) + &
74913176000 12.0*intz(3))
750 enddo
751 enddo ; endif
752
753 ! 3. Compute horizontal integrals in the y direction
754111600 if (present(inty_dpa)) then ; do J=Jsq,Jeq
75513285800 do i=HI%isc,HI%iec
756 ! Corner values of T and S
757 ! hWght is the distance measure by which the cell is violation of
758 ! hydrostatic consistency. For large hWght we bias the interpolation
759 ! of T,S along the top and bottom integrals, almost like thickness
760 ! weighting.
761 ! Note: To work in terrain following coordinates we could offset
762 ! this distance by the layer thickness to replicate other models.
763 hWght = massWeightToggle * &
76413176000 max(0., -bathyT(i,j)-e(i,j+1,K), -bathyT(i,j+1)-e(i,j,K))
765 ! CY: The below code just uses top interface, which may be bad in high res open ocean
766 ! We want something like if (pa(j+1,k+1)<pa(j,1)) or (pa(j+1,1) <pa(i,j,k+1)) then...
767 ! but pressures are not passed through to this submodule, and tv just has surface press.
768 !if ((p(i,j+1,k+1)<p(i,j,1)).or.(tv%p(i,j+1,k+1)<tv%p(i,j,1))) then
769 hWghtTop = TopWeightToggle * &
77013176000 max(0., e(i,j+1,K+1)-e(i,j,1), e(i,j,K+1)-e(i,j+1,1))
771 !else ! pressure criteria not activated
772 ! hWghtTop = 0.
773 !endif
774 ! Set it to be max of the bottom and top hWghts:
77513176000 hWght = max(hWght, hWghtTop)
776 ! If both sides are nonvanished, then set it back to zero.
77713176000 if (((e(i,j,K) - e(i,j,K+1)) > h_nonvanished) .and. ((e(i,j+1,K) - e(i,j+1,K+1)) > h_nonvanished)) then
77813176000 hWght = massWeightNVonlyToggle * hWght
779 endif
780
78113176000 if (hWght > 0.) then
7823174185 hL = (e(i,j,K) - e(i,j,K+1)) + dz_subroundoff
7833174185 hR = (e(i,j+1,K) - e(i,j+1,K+1)) + dz_subroundoff
7843174185 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
7853174185 iDenom = 1./( hWght*(hR + hL) + hL*hR )
7863174185 Ttl = ( (hWght*hR)*T_t(i,j+1,k) + (hWght*hL + hR*hL)*T_t(i,j,k) ) * iDenom
7873174185 Ttr = ( (hWght*hL)*T_t(i,j,k) + (hWght*hR + hR*hL)*T_t(i,j+1,k) ) * iDenom
7883174185 Tbl = ( (hWght*hR)*T_b(i,j+1,k) + (hWght*hL + hR*hL)*T_b(i,j,k) ) * iDenom
7893174185 Tbr = ( (hWght*hL)*T_b(i,j,k) + (hWght*hR + hR*hL)*T_b(i,j+1,k) ) * iDenom
7903174185 Stl = ( (hWght*hR)*S_t(i,j+1,k) + (hWght*hL + hR*hL)*S_t(i,j,k) ) * iDenom
7913174185 Str = ( (hWght*hL)*S_t(i,j,k) + (hWght*hR + hR*hL)*S_t(i,j+1,k) ) * iDenom
7923174185 Sbl = ( (hWght*hR)*S_b(i,j+1,k) + (hWght*hL + hR*hL)*S_b(i,j,k) ) * iDenom
7933174185 Sbr = ( (hWght*hL)*S_b(i,j,k) + (hWght*hR + hR*hL)*S_b(i,j+1,k) ) * iDenom
794 else
79510001815 Ttl = T_t(i,j,k) ; Tbl = T_b(i,j,k) ; Ttr = T_t(i,j+1,k) ; Tbr = T_b(i,j+1,k)
79610001815 Stl = S_t(i,j,k) ; Sbl = S_b(i,j,k) ; Str = S_t(i,j+1,k) ; Sbr = S_b(i,j+1,k)
797 endif
798
79952813800 do m=2,4
80039528000 w_left = wt_t(m) ; w_right = wt_b(m)
80139528000 dz_y(m,i) = (w_left*(e(i,j,K) - e(i,j,K+1))) + (w_right*(e(i,j+1,K) - e(i,j+1,K+1)))
802
803 ! Salinity and temperature points are linearly interpolated in
804 ! the horizontal. The subscript (1) refers to the top value in
805 ! the vertical profile while subscript (5) refers to the bottom
806 ! value in the vertical profile.
80739528000 pos = i*15+(m-2)*5
80839528000 T15(pos+1) = (w_left*Ttl) + (w_right*Ttr)
80939528000 T15(pos+5) = (w_left*Tbl) + (w_right*Tbr)
810
81139528000 S15(pos+1) = (w_left*Stl) + (w_right*Str)
81239528000 S15(pos+5) = (w_left*Sbl) + (w_right*Sbr)
813
81439528000 p15(pos+1) = -GxRho * ((w_left*(e(i,j,K)-z0pres(i,j))) + (w_right*(e(i,j+1,K)-z0pres(i,j+1))))
815
816 ! Pressure
817197640000 do n=2,5
818197640000 p15(pos+n) = p15(pos+n-1) + GxRho*0.25*dz_y(m,i)
819 enddo
820
821 ! Salinity and temperature (linear interpolation in the vertical)
822158112000 do n=2,4
823118584000 S15(pos+n) = wt_t(n) * S15(pos+1) + wt_b(n) * S15(pos+5)
824158112000 T15(pos+n) = wt_t(n) * T15(pos+1) + wt_b(n) * T15(pos+5)
825 enddo
82639528000 if (use_varT) T215(pos+1:pos+5) = (w_left*tv%varT(i,j,k)) + (w_right*tv%varT(i,j+1,k))
82739528000 if (use_covarTS) TS15(pos+1:pos+5) = (w_left*tv%covarTS(i,j,k)) + (w_right*tv%covarTS(i,j+1,k))
82852704000 if (use_varS) S215(pos+1:pos+5) = (w_left*tv%varS(i,j,k)) + (w_right*tv%varS(i,j+1,k))
829 enddo
830 enddo
831
832109800 if (use_stanley_eos) then
833 call calculate_density(T15(15*HI%isc+1:), S15(15*HI%isc+1:), p15(15*HI%isc+1:), &
834 T215(15*HI%isc+1:), TS15(15*HI%isc+1:), S215(15*HI%isc+1:), &
8350 r15(15*HI%isc+1:), EOS, EOSdom_h15, rho_ref=rho_ref)
836 else
837109800 if (use_rho_ref) then
838 call calculate_density(T15(15*HI%isc+1:), S15(15*HI%isc+1:), p15(15*HI%isc+1:), &
839109800 r15(15*HI%isc+1:), EOS, EOSdom_h15, rho_ref=rho_ref)
840 else
841 call calculate_density(T15(15*HI%isc+1:), S15(15*HI%isc+1:), p15(15*HI%isc+1:), &
8420 r15(15*HI%isc+1:), EOS, EOSdom_h15)
843 endif
844 endif
845
84613287600 do i=HI%isc,HI%iec
84713176000 intz(1) = dpa(i,j) ; intz(5) = dpa(i,j+1)
848
849 ! Use Boole's rule to estimate the pressure anomaly change.
85013176000 if (use_rho_ref) then
85152704000 do m = 2,4
85239528000 pos = i*15+(m-2)*5
853 intz(m) = (G_e*dz_y(m,i)*( C1_90*(7.0*(r15(pos+1)+r15(pos+5)) + &
854 32.0*(r15(pos+2)+r15(pos+4)) + &
85552704000 12.0*r15(pos+3)) ))
856 enddo
857 else
8580 do m = 2,4
8590 pos = i*15+(m-2)*5
860 intz(m) = (G_e*dz_y(m,i)*( C1_90*(7.0*(r15(pos+1)+r15(pos+5)) + &
861 32.0*(r15(pos+2)+r15(pos+4)) + &
8620 12.0*r15(pos+3)) - rho_ref ))
863 enddo
864 endif
865 ! Use Boole's rule to integrate the values.
866 inty_dpa(i,J) = C1_90*(7.0*(intz(1)+intz(5)) + 32.0*(intz(2)+intz(4)) + &
86713285800 12.0*intz(3))
868 enddo
869 enddo ; endif
870
8717200end subroutine int_density_dz_generic_plm
872
873
874!> Compute pressure gradient force integrals for layer "k" and the case where T and S
875!! are parabolic profiles
8760subroutine int_density_dz_generic_ppm(k, tv, T_t, T_b, S_t, S_b, e, &
8770 rho_ref, rho_0, G_e, dz_subroundoff, bathyT, HI, GV, EOS, US, use_stanley_eos, &
8780 dpa, intz_dpa, intx_dpa, inty_dpa, MassWghtInterp, Z_0p, &
879 MassWghtInterpVanOnly, h_nv)
880 integer, intent(in) :: k !< Layer index to calculate integrals for
881 type(hor_index_type), intent(in) :: HI !< Ocean horizontal index structures for the input arrays
882 type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure
883 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamic variables
884 real, dimension(SZI_(HI),SZJ_(HI),SZK_(GV)), &
885 intent(in) :: T_t !< Potential temperature at the cell top [C ~> degC]
886 real, dimension(SZI_(HI),SZJ_(HI),SZK_(GV)), &
887 intent(in) :: T_b !< Potential temperature at the cell bottom [C ~> degC]
888 real, dimension(SZI_(HI),SZJ_(HI),SZK_(GV)), &
889 intent(in) :: S_t !< Salinity at the cell top [S ~> ppt]
890 real, dimension(SZI_(HI),SZJ_(HI),SZK_(GV)), &
891 intent(in) :: S_b !< Salinity at the cell bottom [S ~> ppt]
892 real, dimension(SZI_(HI),SZJ_(HI),SZK_(GV)+1), &
893 intent(in) :: e !< Height of interfaces [Z ~> m]
894 real, intent(in) :: rho_ref !< A mean density [R ~> kg m-3], that is
895 !! subtracted out to reduce the magnitude of each of the integrals.
896 real, intent(in) :: rho_0 !< A density [R ~> kg m-3], that is used to calculate
897 !! the pressure (as p~=-z*rho_0*G_e) used in the equation of state.
898 real, intent(in) :: G_e !< The Earth's gravitational acceleration [L2 Z-1 T-2 ~> m s-2]
899 real, intent(in) :: dz_subroundoff !< A minuscule thickness change [Z ~> m]
900 real, dimension(SZI_(HI),SZJ_(HI)), &
901 intent(in) :: bathyT !< The depth of the bathymetry [Z ~> m]
902 type(EOS_type), intent(in) :: EOS !< Equation of state structure
903 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
904 logical, intent(in) :: use_stanley_eos !< If true, turn on Stanley SGS T variance parameterization
905 real, dimension(SZI_(HI),SZJ_(HI)), &
906 intent(inout) :: dpa !< The change in the pressure anomaly across the layer [R L2 T-2 ~> Pa]
907 real, dimension(SZI_(HI),SZJ_(HI)), &
908 optional, intent(inout) :: intz_dpa !< The integral through the thickness of the layer of
909 !! the pressure anomaly relative to the anomaly at the
910 !! top of the layer [R L2 Z T-2 ~> Pa m]
911 real, dimension(SZIB_(HI),SZJ_(HI)), &
912 optional, intent(inout) :: intx_dpa !< The integral in x of the difference between the
913 !! pressure anomaly at the top and bottom of the layer
914 !! divided by the x grid spacing [R L2 T-2 ~> Pa]
915 real, dimension(SZI_(HI),SZJB_(HI)), &
916 optional, intent(inout) :: inty_dpa !< The integral in y of the difference between the
917 !! pressure anomaly at the top and bottom of the layer
918 !! divided by the y grid spacing [R L2 T-2 ~> Pa]
919 integer, optional, intent(in) :: MassWghtInterp !< A flag indicating whether and how to use
920 !! mass weighting to interpolate T/S in integrals
921 logical, optional, intent(in) :: MassWghtInterpVanOnly !< If true, does not do mass weighting
922 !! of T/S unless one side smaller than h_nv (i.e. vanished)
923 real, optional, intent(in) :: h_nv !< Nonvanished height [Z ~> m]
924
925 real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), &
926 optional, intent(in) :: Z_0p !< The height at which the pressure is 0 [Z ~> m]
927
928! This subroutine calculates (by numerical quadrature) integrals of
929! pressure anomalies across layers, which are required for calculating the
930! finite-volume form pressure accelerations in a Boussinesq model. The one
931! potentially dodgy assumption here is that rho_0 is used both in the denominator
932! of the accelerations, and in the pressure used to calculated density (the
933! latter being -z*rho_0*G_e). These two uses could be separated if need be.
934!
935! It is assumed that the salinity and temperature profiles are parabolic in the
936! vertical. The top and bottom values within each layer are provided and
937! a parabolic interpolation is used to compute intermediate values.
938
939 ! Local variables
9400 real :: T5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Temperatures along a line of subgrid locations [C ~> degC]
9410 real :: S5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Salinities along a line of subgrid locations [S ~> ppt]
9420 real :: T25((5*HI%iscB+1):(5*(HI%iecB+2))) ! SGS temperature variance along a line of subgrid
943 ! locations [C2 ~> degC2]
9440 real :: TS5((5*HI%iscB+1):(5*(HI%iecB+2))) ! SGS temp-salt covariance along a line of subgrid
945 ! locations [C S ~> degC ppt]
9460 real :: S25((5*HI%iscB+1):(5*(HI%iecB+2))) ! SGS salinity variance along a line of subgrid locations [S2 ~> ppt2]
9470 real :: p5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Pressures along a line of subgrid locations [R L2 T-2 ~> Pa]
9480 real :: r5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Densities anomalies along a line of subgrid
949 ! locations [R ~> kg m-3]
9500 real :: T15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Temperatures at an array of subgrid locations [C ~> degC]
9510 real :: S15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Salinities at an array of subgrid locations [S ~> ppt]
9520 real :: T215((15*HI%iscB+1):(15*(HI%iecB+1))) ! SGS temperature variance along a line of subgrid
953 ! locations [C2 ~> degC2]
9540 real :: TS15((15*HI%iscB+1):(15*(HI%iecB+1))) ! SGS temp-salt covariance along a line of subgrid
955 ! locations [C S ~> degC ppt]
9560 real :: S215((15*HI%iscB+1):(15*(HI%iecB+1))) ! SGS salinity variance along a line of subgrid
957 ! locations [S2 ~> ppt2]
9580 real :: p15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Pressures at an array of subgrid locations [R L2 T-2 ~> Pa]
9590 real :: r15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Densities at an array of subgrid locations [R ~> kg m-3]
960 real :: wt_t(5), wt_b(5) ! Top and bottom weights [nondim]
961 real :: rho_anom ! The integrated density anomaly [R ~> kg m-3]
962 real :: w_left, w_right ! Left and right weights [nondim]
963 real :: intz(5) ! The gravitational acceleration times the integrals of density
964 ! with height at the 5 sub-column locations [R L2 T-2 ~> Pa]
965 real, parameter :: C1_90 = 1.0/90.0 ! A rational constant [nondim]
966 real :: GxRho ! The gravitational acceleration times density [R L2 Z-1 T-2 ~> kg m-2 s-2]
967 real :: dz ! Layer thicknesses at tracer points [Z ~> m]
9680 real :: dz_x(5,HI%iscB:HI%iecB) ! Layer thicknesses along an x-line of subgrid locations [Z ~> m]
9690 real :: dz_y(5,HI%isc:HI%iec) ! Layer thicknesses along a y-line of subgrid locations [Z ~> m]
970 real :: massWeightToggle ! A non-dimensional toggle factor for near-bottom mass weighting (0 or 1) [nondim]
971 real :: TopWeightToggle ! A non-dimensional toggle factor for near-surface mass weighting (0 or 1) [nondim]
972 real :: massWeightNVonlyToggle ! A non-dimensional toggle factor for only using mass weighting
973 ! if at least one side vanished (0 or 1) [nondim]
974 real :: Ttl, Tbl, Tml, Ttr, Tbr, Tmr ! Temperatures at the velocity cell corners [C ~> degC]
975 real :: Stl, Sbl, Sml, Str, Sbr, Smr ! Salinities at the velocity cell corners [S ~> ppt]
976 real :: s6 ! PPM curvature coefficient for S [S ~> ppt]
977 real :: t6 ! PPM curvature coefficient for T [C ~> degC]
978 real :: T_top, T_mn, T_bot ! Left edge, cell mean and right edge values used in PPM reconstructions of T [C ~> degC]
979 real :: S_top, S_mn, S_bot ! Left edge, cell mean and right edge values used in PPM reconstructions of S [S ~> ppt]
9800 real :: z0pres(HI%isd:HI%ied,HI%jsd:HI%jed) ! The height at which the pressure is zero [Z ~> m]
981 real :: hWght ! A topographically limited thickness weight [Z ~> m]
982 real :: hWghtTop ! A surface displacement limited thickness weight [Z ~> m]
983 real :: hL, hR ! Thicknesses to the left and right [Z ~> m]
984 real :: iDenom ! The denominator of the thickness weight expressions [Z-2 ~> m-2]
985 real :: h_nonvanished ! nonvanished height [Z ~> m]
986 integer, dimension(2) :: EOSdom_h5 ! The 5-point h-point i-computational domain for the equation of state
987 integer, dimension(2) :: EOSdom_q15 ! The 3x5-point q-point i-computational domain for the equation of state
988 integer, dimension(2) :: EOSdom_h15 ! The 3x5-point h-point i-computational domain for the equation of state
989 integer :: Isq, Ieq, Jsq, Jeq, i, j, m, n, pos
990 logical :: use_PPM ! If false, assume zero curvature in reconstruction, i.e. PLM
991 logical :: use_varT, use_varS, use_covarTS ! Logicals for SGS variances fields
992
9930 Isq = HI%IscB ; Ieq = HI%IecB ; Jsq = HI%JscB ; Jeq = HI%JecB
994
9950 GxRho = G_e * rho_0
9960 if (present(Z_0p)) then
9970 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
9980 z0pres(i,j) = Z_0p(i,j)
999 enddo ; enddo
1000 else
10010 z0pres(:,:) = 0.0
1002 endif
10030 massWeightToggle = 0. ; TopWeightToggle = 0.
10040 if (present(MassWghtInterp)) then
10050 if (BTEST(MassWghtInterp, 0)) massWeightToggle = 1.
10060 if (BTEST(MassWghtInterp, 1)) TopWeightToggle = 1.
1007 endif
10080 massWeightNVonlyToggle = 1.
10090 if (present(MassWghtInterpVanOnly)) then
10100 if (MassWghtInterpVanOnly) massWeightNVonlyToggle = 0.
1011 endif
10120 h_nonvanished = 0.
10130 if (present(h_nv)) then
10140 h_nonvanished = h_nv
1015 endif
1016
1017 ! In event PPM calculation is bypassed with use_PPM=False
10180 s6 = 0.
10190 t6 = 0.
10200 use_PPM = .true. ! This is a place-holder to allow later re-use of this function
1021
10220 use_varT = .false. !ensure initialized
10230 use_covarTS = .false.
10240 use_varS = .false.
10250 if (use_stanley_eos) then
10260 use_varT = associated(tv%varT)
10270 use_covarTS = associated(tv%covarTS)
10280 use_varS = associated(tv%varS)
1029 endif
1030
10310 T25(:) = 0.
10320 TS5(:) = 0.
10330 S25(:) = 0.
10340 T215(:) = 0.
10350 TS15(:) = 0.
10360 S215(:) = 0.
1037
10380 do n = 1, 5
10390 wt_t(n) = 0.25 * real(5-n)
10400 wt_b(n) = 1.0 - wt_t(n)
1041 enddo
1042
1043 ! Set the loop ranges for equation of state calculations at various points.
10440 EOSdom_h5(1) = 1 ; EOSdom_h5(2) = 5*(Ieq-Isq+2)
10450 EOSdom_q15(1) = 1 ; EOSdom_q15(2) = 15*(Ieq-Isq+1)
10460 EOSdom_h15(1) = 1 ; EOSdom_h15(2) = 15*(HI%iec-HI%isc+1)
1047
1048 ! 1. Compute vertical integrals
10490 do j=Jsq,Jeq+1
10500 do i=Isq,Ieq+1
10510 if (use_PPM) then
1052 ! Curvature coefficient of the parabolas
10530 s6 = 3.0 * ( 2.0*tv%S(i,j,k) - ( S_t(i,j,k) + S_b(i,j,k) ) )
10540 t6 = 3.0 * ( 2.0*tv%T(i,j,k) - ( T_t(i,j,k) + T_b(i,j,k) ) )
1055 endif
10560 dz = e(i,j,K) - e(i,j,K+1)
10570 do n=1,5
10580 p5(I*5+n) = -GxRho*((e(i,j,K) - z0pres(i,j)) - 0.25*real(n-1)*dz)
1059 ! Salinity and temperature points are reconstructed with PPM
10600 S5(I*5+n) = wt_t(n) * S_t(i,j,k) + wt_b(n) * ( S_b(i,j,k) + s6 * wt_t(n) )
10610 T5(I*5+n) = wt_t(n) * T_t(i,j,k) + wt_b(n) * ( T_b(i,j,k) + t6 * wt_t(n) )
1062 enddo
10630 if (use_stanley_eos) then
10640 if (use_varT) T25(I*5+1:I*5+5) = tv%varT(i,j,k)
10650 if (use_covarTS) TS5(I*5+1:I*5+5) = tv%covarTS(i,j,k)
10660 if (use_varS) S25(I*5+1:I*5+5) = tv%varS(i,j,k)
1067 endif
1068 enddo
1069
10700 if (use_stanley_eos) then
10710 call calculate_density(T5, S5, p5, T25, TS5, S25, r5, EOS, EOSdom_h5, rho_ref=rho_ref)
1072 else
10730 call calculate_density(T5, S5, p5, r5, EOS, EOSdom_h5, rho_ref=rho_ref)
1074 endif
1075
10760 do i=Isq,Ieq+1
10770 dz = e(i,j,K) - e(i,j,K+1)
1078 ! Use Boole's rule to estimate the pressure anomaly change.
10790 rho_anom = C1_90*(7.0*(r5(i*5+1)+r5(i*5+5)) + 32.0*(r5(i*5+2)+r5(i*5+4)) + 12.0*r5(i*5+3))
10800 dpa(i,j) = G_e*dz*rho_anom
10810 if (present(intz_dpa)) then
1082 ! Use a Boole's-rule-like fifth-order accurate estimate of
1083 ! the double integral of the pressure anomaly.
1084 intz_dpa(i,j) = 0.5*G_e*dz**2 * &
10850 (rho_anom - C1_90*(16.0*(r5(i*5+4)-r5(i*5+2)) + 7.0*(r5(i*5+5)-r5(i*5+1))) )
1086 endif
1087 enddo ! end loop on i
1088 enddo ! end loop on j
1089
1090 ! 2. Compute horizontal integrals in the x direction
10910 if (present(intx_dpa)) then ; do j=HI%jsc,HI%jec
10920 do I=Isq,Ieq
1093 ! Corner values of T and S
1094 ! hWght is the distance measure by which the cell is violation of
1095 ! hydrostatic consistency. For large hWght we bias the interpolation
1096 ! of T,S along the top and bottom integrals, almost like thickness
1097 ! weighting.
1098 ! Note: To work in terrain following coordinates we could offset
1099 ! this distance by the layer thickness to replicate other models.
1100 hWght = massWeightToggle * &
11010 max(0., -bathyT(i,j)-e(i+1,j,K), -bathyT(i+1,j)-e(i,j,K))
1102 hWghtTop = TopWeightToggle * &
11030 max(0., e(i+1,j,K+1)-e(i,j,1), e(i,j,K+1)-e(i+1,j,1))
11040 hWght = max(hWght, hWghtTop)
1105 ! If both sides are nonvanished, then set it back to zero.
11060 if (((e(i,j,K) - e(i,j,K+1)) > h_nonvanished) .and. ((e(i+1,j,K) - e(i+1,j,K+1)) > h_nonvanished)) then
11070 hWght = massWeightNVonlyToggle * hWght
1108 endif
11090 if (hWght > 0.) then
11100 hL = (e(i,j,K) - e(i,j,K+1)) + dz_subroundoff
11110 hR = (e(i+1,j,K) - e(i+1,j,K+1)) + dz_subroundoff
11120 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
11130 iDenom = 1./( hWght*(hR + hL) + hL*hR )
11140 Ttl = ( (hWght*hR)*T_t(i+1,j,k) + (hWght*hL + hR*hL)*T_t(i,j,k) ) * iDenom
11150 Tbl = ( (hWght*hR)*T_b(i+1,j,k) + (hWght*hL + hR*hL)*T_b(i,j,k) ) * iDenom
11160 Tml = ( (hWght*hR)*tv%T(i+1,j,k)+ (hWght*hL + hR*hL)*tv%T(i,j,k) ) * iDenom
11170 Ttr = ( (hWght*hL)*T_t(i,j,k) + (hWght*hR + hR*hL)*T_t(i+1,j,k) ) * iDenom
11180 Tbr = ( (hWght*hL)*T_b(i,j,k) + (hWght*hR + hR*hL)*T_b(i+1,j,k) ) * iDenom
11190 Tmr = ( (hWght*hL)*tv%T(i,j,k) + (hWght*hR + hR*hL)*tv%T(i+1,j,k) ) * iDenom
11200 Stl = ( (hWght*hR)*S_t(i+1,j,k) + (hWght*hL + hR*hL)*S_t(i,j,k) ) * iDenom
11210 Sbl = ( (hWght*hR)*S_b(i+1,j,k) + (hWght*hL + hR*hL)*S_b(i,j,k) ) * iDenom
11220 Sml = ( (hWght*hR)*tv%S(i+1,j,k) + (hWght*hL + hR*hL)*tv%S(i,j,k) ) * iDenom
11230 Str = ( (hWght*hL)*S_t(i,j,k) + (hWght*hR + hR*hL)*S_t(i+1,j,k) ) * iDenom
11240 Sbr = ( (hWght*hL)*S_b(i,j,k) + (hWght*hR + hR*hL)*S_b(i+1,j,k) ) * iDenom
11250 Smr = ( (hWght*hL)*tv%S(i,j,k) + (hWght*hR + hR*hL)*tv%S(i+1,j,k) ) * iDenom
1126 else
11270 Ttl = T_t(i,j,k) ; Tbl = T_b(i,j,k) ; Ttr = T_t(i+1,j,k) ; Tbr = T_b(i+1,j,k)
11280 Tml = tv%T(i,j,k) ; Tmr = tv%T(i+1,j,k)
11290 Stl = S_t(i,j,k) ; Sbl = S_b(i,j,k) ; Str = S_t(i+1,j,k) ; Sbr = S_b(i+1,j,k)
11300 Sml = tv%S(i,j,k) ; Smr = tv%S(i+1,j,k)
1131 endif
1132
11330 do m=2,4
11340 w_left = wt_t(m) ; w_right = wt_b(m)
1135
1136 ! Salinity and temperature points are linearly interpolated in
1137 ! the horizontal. The subscript (1) refers to the top value in
1138 ! the vertical profile while subscript (5) refers to the bottom
1139 ! value in the vertical profile.
11400 T_top = (w_left*Ttl) + (w_right*Ttr)
11410 T_mn = (w_left*Tml) + (w_right*Tmr)
11420 T_bot = (w_left*Tbl) + (w_right*Tbr)
1143
11440 S_top = (w_left*Stl) + (w_right*Str)
11450 S_mn = (w_left*Sml) + (w_right*Smr)
11460 S_bot = (w_left*Sbl) + (w_right*Sbr)
1147
1148 ! Pressure
11490 dz_x(m,i) = (w_left*(e(i,j,K) - e(i,j,K+1))) + (w_right*(e(i+1,j,K) - e(i+1,j,K+1)))
1150
11510 pos = i*15+(m-2)*5
11520 p15(pos+1) = -GxRho * ((w_left*(e(i,j,K)-z0pres(i,j))) + (w_right*(e(i+1,j,K)-z0pres(i+1,j))))
11530 do n=2,5
11540 p15(pos+n) = p15(pos+n-1) + GxRho*0.25*dz_x(m,i)
1155 enddo
1156
1157 ! Parabolic reconstructions in the vertical for T and S
11580 if (use_PPM) then
1159 ! Coefficients of the parabolas
11600 s6 = 3.0 * ( 2.0*S_mn - ( S_top + S_bot ) )
11610 t6 = 3.0 * ( 2.0*T_mn - ( T_top + T_bot ) )
1162 endif
11630 do n=1,5
11640 S15(pos+n) = wt_t(n) * S_top + wt_b(n) * ( S_bot + s6 * wt_t(n) )
11650 T15(pos+n) = wt_t(n) * T_top + wt_b(n) * ( T_bot + t6 * wt_t(n) )
1166 enddo
11670 if (use_stanley_eos) then
11680 if (use_varT) T215(pos+1:pos+5) = (w_left*tv%varT(i,j,k)) + (w_right*tv%varT(i+1,j,k))
11690 if (use_covarTS) TS15(pos+1:pos+5) = (w_left*tv%covarTS(i,j,k)) + (w_right*tv%covarTS(i+1,j,k))
11700 if (use_varS) S215(pos+1:pos+5) = (w_left*tv%varS(i,j,k)) + (w_right*tv%varS(i+1,j,k))
1171 endif
11720 if (use_stanley_eos) then
11730 call calculate_density(T5, S5, p5, T25, TS5, S25, r5, EOS, rho_ref=rho_ref)
1174 else
11750 call calculate_density(T5, S5, p5, r5, EOS, rho_ref=rho_ref)
1176 endif
1177 enddo
1178 enddo
1179
11800 if (use_stanley_eos) then
11810 call calculate_density(T15, S15, p15, T215, TS15, S215, r15, EOS, EOSdom_q15, rho_ref=rho_ref)
1182 else
11830 call calculate_density(T15, S15, p15, r15, EOS, EOSdom_q15, rho_ref=rho_ref)
1184 endif
1185
11860 do I=Isq,Ieq
11870 do m=2,4
11880 pos = i*15+(m-2)*5
1189 ! Use Boole's rule to estimate the pressure anomaly change.
1190 intz(m) = (G_e*dz_x(m,i)*(C1_90*( 7.0*(r15(pos+1)+r15(pos+5)) + &
1191 32.0*(r15(pos+2)+r15(pos+4)) + &
11920 12.0*r15(pos+3)) ))
1193 enddo ! m
11940 intz(1) = dpa(i,j) ; intz(5) = dpa(i+1,j)
1195
1196 ! Use Boole's rule to integrate the bottom pressure anomaly values in x.
11970 intx_dpa(I,j) = C1_90*(7.0*(intz(1)+intz(5)) + 32.0*(intz(2)+intz(4)) + 12.0*intz(3))
1198
1199 enddo
1200 enddo ; endif
1201
1202 ! 3. Compute horizontal integrals in the y direction
12030 if (present(inty_dpa)) then ; do J=Jsq,Jeq
12040 do i=HI%isc,HI%iec
1205 ! Corner values of T and S
1206 ! hWght is the distance measure by which the cell is violation of
1207 ! hydrostatic consistency. For large hWght we bias the interpolation
1208 ! of T,S along the top and bottom integrals, almost like thickness
1209 ! weighting.
1210 ! Note: To work in terrain following coordinates we could offset
1211 ! this distance by the layer thickness to replicate other models.
1212 hWght = massWeightToggle * &
12130 max(0., -bathyT(i,j)-e(i,j+1,K), -bathyT(i,j+1)-e(i,j,K))
1214 hWghtTop = TopWeightToggle * &
12150 max(0., e(i,j+1,K+1)-e(i,j,1), e(i,j,K+1)-e(i,j+1,1))
12160 hWght = max(hWght, hWghtTop)
1217 ! If both sides are nonvanished, then set it back to zero.
12180 if (((e(i,j,K) - e(i,j,K+1)) > h_nonvanished) .and. ((e(i,j+1,K) - e(i,j+1,K+1)) > h_nonvanished)) then
12190 hWght = massWeightNVonlyToggle * hWght
1220 endif
12210 if (hWght > 0.) then
12220 hL = (e(i,j,K) - e(i,j,K+1)) + dz_subroundoff
12230 hR = (e(i,j+1,K) - e(i,j+1,K+1)) + dz_subroundoff
12240 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
12250 iDenom = 1./( hWght*(hR + hL) + hL*hR )
12260 Ttl = ( (hWght*hR)*T_t(i,j+1,k) + (hWght*hL + hR*hL)*T_t(i,j,k) ) * iDenom
12270 Tbl = ( (hWght*hR)*T_b(i,j+1,k) + (hWght*hL + hR*hL)*T_b(i,j,k) ) * iDenom
12280 Tml = ( (hWght*hR)*tv%T(i,j+1,k)+ (hWght*hL + hR*hL)*tv%T(i,j,k) ) * iDenom
12290 Ttr = ( (hWght*hL)*T_t(i,j,k) + (hWght*hR + hR*hL)*T_t(i,j+1,k) ) * iDenom
12300 Tbr = ( (hWght*hL)*T_b(i,j,k) + (hWght*hR + hR*hL)*T_b(i,j+1,k) ) * iDenom
12310 Tmr = ( (hWght*hL)*tv%T(i,j,k) + (hWght*hR + hR*hL)*tv%T(i,j+1,k) ) * iDenom
12320 Stl = ( (hWght*hR)*S_t(i,j+1,k) + (hWght*hL + hR*hL)*S_t(i,j,k) ) * iDenom
12330 Sbl = ( (hWght*hR)*S_b(i,j+1,k) + (hWght*hL + hR*hL)*S_b(i,j,k) ) * iDenom
12340 Sml = ( (hWght*hR)*tv%S(i,j+1,k)+ (hWght*hL + hR*hL)*tv%S(i,j,k) ) * iDenom
12350 Str = ( (hWght*hL)*S_t(i,j,k) + (hWght*hR + hR*hL)*S_t(i,j+1,k) ) * iDenom
12360 Sbr = ( (hWght*hL)*S_b(i,j,k) + (hWght*hR + hR*hL)*S_b(i,j+1,k) ) * iDenom
12370 Smr = ( (hWght*hL)*tv%S(i,j,k) + (hWght*hR + hR*hL)*tv%S(i,j+1,k) ) * iDenom
1238 else
12390 Ttl = T_t(i,j,k) ; Tbl = T_b(i,j,k) ; Ttr = T_t(i,j+1,k) ; Tbr = T_b(i,j+1,k)
12400 Tml = tv%T(i,j,k) ; Tmr = tv%T(i,j+1,k)
12410 Stl = S_t(i,j,k) ; Sbl = S_b(i,j,k) ; Str = S_t(i,j+1,k) ; Sbr = S_b(i,j+1,k)
12420 Sml = tv%S(i,j,k) ; Smr = tv%S(i,j+1,k)
1243 endif
1244
12450 do m=2,4
12460 w_left = wt_t(m) ; w_right = wt_b(m)
1247
1248 ! Salinity and temperature points are linearly interpolated in
1249 ! the horizontal. The subscript (1) refers to the top value in
1250 ! the vertical profile while subscript (5) refers to the bottom
1251 ! value in the vertical profile.
12520 T_top = (w_left*Ttl) + (w_right*Ttr)
12530 T_mn = (w_left*Tml) + (w_right*Tmr)
12540 T_bot = (w_left*Tbl) + (w_right*Tbr)
1255
12560 S_top = (w_left*Stl) + (w_right*Str)
12570 S_mn = (w_left*Sml) + (w_right*Smr)
12580 S_bot = (w_left*Sbl) + (w_right*Sbr)
1259
1260 ! Pressure
12610 dz_y(m,i) = (w_left*(e(i,j,K) - e(i,j,K+1))) + (w_right*(e(i,j+1,K) - e(i,j+1,K+1)))
1262
12630 pos = i*15+(m-2)*5
12640 p15(pos+1) = -GxRho * ((w_left*(e(i,j,K)-z0pres(i,j))) + (w_right*(e(i,j+1,K)-z0pres(i,j+1))))
12650 do n=2,5
12660 p15(pos+n) = p15(pos+n-1) + GxRho*0.25*dz_y(m,i)
1267 enddo
1268
1269 ! Parabolic reconstructions in the vertical for T and S
12700 if (use_PPM) then
1271 ! Coefficients of the parabolas
12720 s6 = 3.0 * ( 2.0*S_mn - ( S_top + S_bot ) )
12730 t6 = 3.0 * ( 2.0*T_mn - ( T_top + T_bot ) )
1274 endif
12750 do n=1,5
12760 S15(pos+n) = wt_t(n) * S_top + wt_b(n) * ( S_bot + s6 * wt_t(n) )
12770 T15(pos+n) = wt_t(n) * T_top + wt_b(n) * ( T_bot + t6 * wt_t(n) )
1278 enddo
1279
12800 if (use_stanley_eos) then
12810 if (use_varT) T215(pos+1:pos+5) = (w_left*tv%varT(i,j,k)) + (w_right*tv%varT(i,j+1,k))
12820 if (use_covarTS) TS15(pos+1:pos+5) = (w_left*tv%covarTS(i,j,k)) + (w_right*tv%covarTS(i,j+1,k))
12830 if (use_varS) S215(pos+1:pos+5) = (w_left*tv%varS(i,j,k)) + (w_right*tv%varS(i,j+1,k))
1284 endif
1285 enddo
1286 enddo
1287
12880 if (use_stanley_eos) then
1289 call calculate_density(T15(15*HI%isc+1:), S15(15*HI%isc+1:), p15(15*HI%isc+1:), &
1290 T215(15*HI%isc+1:), TS15(15*HI%isc+1:), S215(15*HI%isc+1:), &
12910 r15(15*HI%isc+1:), EOS, EOSdom_h15, rho_ref=rho_ref)
1292 else
1293 call calculate_density(T15(15*HI%isc+1:), S15(15*HI%isc+1:), p15(15*HI%isc+1:), &
12940 r15(15*HI%isc+1:), EOS, EOSdom_h15, rho_ref=rho_ref)
1295 endif
1296
12970 do i=HI%isc,HI%iec
12980 do m=2,4
1299 ! Use Boole's rule to estimate the pressure anomaly change.
13000 pos = i*15+(m-2)*5
1301 intz(m) = (G_e*dz_y(m,i)*(C1_90*( 7.0*(r15(pos+1)+r15(pos+5)) + &
1302 32.0*(r15(pos+2)+r15(pos+4)) + &
13030 12.0*r15(pos+3)) ))
1304 enddo ! m
13050 intz(1) = dpa(i,j) ; intz(5) = dpa(i,j+1)
1306
1307 ! Use Boole's rule to integrate the bottom pressure anomaly values in y.
13080 inty_dpa(i,J) = C1_90*(7.0*(intz(1)+intz(5)) + 32.0*(intz(2)+intz(4)) + 12.0*intz(3))
1309 enddo
1310 enddo ; endif
1311
13120end subroutine int_density_dz_generic_ppm
1313
1314!> Calls the appropriate subroutine to calculate analytical and nearly-analytical
1315!! integrals in pressure across layers of geopotential anomalies, which are
1316!! required for calculating the finite-volume form pressure accelerations in a
1317!! non-Boussinesq model. There are essentially no free assumptions, apart from the
1318!! use of Boole's rule to do the horizontal integrals, and from a truncation in the
1319!! series for log(1-eps/1+eps) that assumes that |eps| < 0.34.
13200subroutine int_specific_vol_dp(T, S, p_t, p_b, alpha_ref, HI, EOS, US, &
13210 dza, intp_dza, intx_dza, inty_dza, halo_size, &
13220 bathyP, P_surf, dP_tiny, MassWghtInterp, &
1323 MassWghtInterpVanOnly, p_nv)
1324 type(hor_index_type), intent(in) :: HI !< The horizontal index structure
1325 real, dimension(SZI_(HI),SZJ_(HI)), &
1326 intent(in) :: T !< Potential temperature referenced to the surface [C ~> degC]
1327 real, dimension(SZI_(HI),SZJ_(HI)), &
1328 intent(in) :: S !< Salinity [S ~> ppt]
1329 real, dimension(SZI_(HI),SZJ_(HI)), &
1330 intent(in) :: p_t !< Pressure at the top of the layer [R L2 T-2 ~> Pa]
1331 real, dimension(SZI_(HI),SZJ_(HI)), &
1332 intent(in) :: p_b !< Pressure at the bottom of the layer [R L2 T-2 ~> Pa]
1333 real, intent(in) :: alpha_ref !< A mean specific volume that is subtracted out
1334 !! to reduce the magnitude of each of the integrals [R-1 ~> m3 kg-1]
1335 !! The calculation is mathematically identical with different values of
1336 !! alpha_ref, but this reduces the effects of roundoff.
1337 type(EOS_type), intent(in) :: EOS !< Equation of state structure
1338 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1339 real, dimension(SZI_(HI),SZJ_(HI)), &
1340 intent(inout) :: dza !< The change in the geopotential anomaly across
1341 !! the layer [L2 T-2 ~> m2 s-2]
1342 real, dimension(SZI_(HI),SZJ_(HI)), &
1343 optional, intent(inout) :: intp_dza !< The integral in pressure through the layer of the
1344 !! geopotential anomaly relative to the anomaly at the bottom of the
1345 !! layer [R L4 T-4 ~> Pa m2 s-2]
1346 real, dimension(SZIB_(HI),SZJ_(HI)), &
1347 optional, intent(inout) :: intx_dza !< The integral in x of the difference between the
1348 !! geopotential anomaly at the top and bottom of the layer divided by
1349 !! the x grid spacing [L2 T-2 ~> m2 s-2]
1350 real, dimension(SZI_(HI),SZJB_(HI)), &
1351 optional, intent(inout) :: inty_dza !< The integral in y of the difference between the
1352 !! geopotential anomaly at the top and bottom of the layer divided by
1353 !! the y grid spacing [L2 T-2 ~> m2 s-2]
1354 integer, optional, intent(in) :: halo_size !< The width of halo points on which to calculate dza.
1355 real, dimension(SZI_(HI),SZJ_(HI)), &
1356 optional, intent(in) :: bathyP !< The pressure at the bathymetry [R L2 T-2 ~> Pa]
1357 real, dimension(SZI_(HI),SZJ_(HI)), &
1358 optional, intent(in) :: P_surf !< The pressure at the ocean surface [R L2 T-2 ~> Pa]
1359 real, optional, intent(in) :: dP_tiny !< A minuscule pressure change with
1360 !! the same units as p_t [R L2 T-2 ~> Pa]
1361 integer, optional, intent(in) :: MassWghtInterp !< A flag indicating whether and how to use
1362 !! mass weighting to interpolate T/S in integrals
1363 logical, optional, intent(in) :: MassWghtInterpVanOnly !< If true, does not do mass weighting
1364 !! of T/S unless one side smaller than h_nv (i.e. vanished)
1365 real, optional, intent(in) :: p_nv !< Nonvanished pressure [R L2 T-2 ~> Pa]
1366
1367
13680 if (EOS_quadrature(EOS)) then
1369 call int_spec_vol_dp_generic_pcm(T, S, p_t, p_b, alpha_ref, HI, EOS, US, &
1370 dza, intp_dza, intx_dza, inty_dza, halo_size, &
1371 bathyP, P_surf, dP_tiny, MassWghtInterp, &
13720 MassWghtInterpVanOnly, p_nv)
1373 else
1374 call analytic_int_specific_vol_dp(T, S, p_t, p_b, alpha_ref, HI, EOS, &
1375 dza, intp_dza, intx_dza, inty_dza, halo_size, &
13760 bathyP, P_surf, dP_tiny, MassWghtInterp)
1377 endif
1378
13790end subroutine int_specific_vol_dp
1380
1381
1382!> This subroutine calculates integrals of specific volume anomalies in
1383!! pressure across layers, which are required for calculating the finite-volume
1384!! form pressure accelerations in a non-Boussinesq model. There are essentially
1385!! no free assumptions, apart from the use of Boole's rule quadrature to do the integrals.
13860subroutine int_spec_vol_dp_generic_pcm(T, S, p_t, p_b, alpha_ref, HI, EOS, US, dza, &
13870 intp_dza, intx_dza, inty_dza, halo_size, &
13880 bathyP, P_surf, dP_neglect, MassWghtInterp, &
1389 MassWghtInterpVanOnly, p_nv)
1390 type(hor_index_type), intent(in) :: HI !< A horizontal index type structure.
1391 real, dimension(SZI_(HI),SZJ_(HI)), &
1392 intent(in) :: T !< Potential temperature of the layer [C ~> degC]
1393 real, dimension(SZI_(HI),SZJ_(HI)), &
1394 intent(in) :: S !< Salinity of the layer [S ~> ppt]
1395 real, dimension(SZI_(HI),SZJ_(HI)), &
1396 intent(in) :: p_t !< Pressure atop the layer [R L2 T-2 ~> Pa]
1397 real, dimension(SZI_(HI),SZJ_(HI)), &
1398 intent(in) :: p_b !< Pressure below the layer [R L2 T-2 ~> Pa]
1399 real, intent(in) :: alpha_ref !< A mean specific volume that is subtracted out
1400 !! to reduce the magnitude of each of the integrals [R-1 ~> m3 kg-1]
1401 !! The calculation is mathematically identical with different values of
1402 !! alpha_ref, but alpha_ref alters the effects of roundoff, and
1403 !! answers do change.
1404 type(EOS_type), intent(in) :: EOS !< Equation of state structure
1405 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1406 real, dimension(SZI_(HI),SZJ_(HI)), &
1407 intent(inout) :: dza !< The change in the geopotential anomaly
1408 !! across the layer [L2 T-2 ~> m2 s-2]
1409 real, dimension(SZI_(HI),SZJ_(HI)), &
1410 optional, intent(inout) :: intp_dza !< The integral in pressure through the layer of
1411 !! the geopotential anomaly relative to the anomaly at the bottom of the
1412 !! layer [R L4 T-4 ~> Pa m2 s-2]
1413 real, dimension(SZIB_(HI),SZJ_(HI)), &
1414 optional, intent(inout) :: intx_dza !< The integral in x of the difference between
1415 !! the geopotential anomaly at the top and bottom of the layer divided
1416 !! by the x grid spacing [L2 T-2 ~> m2 s-2]
1417 real, dimension(SZI_(HI),SZJB_(HI)), &
1418 optional, intent(inout) :: inty_dza !< The integral in y of the difference between
1419 !! the geopotential anomaly at the top and bottom of the layer divided
1420 !! by the y grid spacing [L2 T-2 ~> m2 s-2]
1421 integer, optional, intent(in) :: halo_size !< The width of halo points on which to calculate dza.
1422 real, dimension(SZI_(HI),SZJ_(HI)), &
1423 optional, intent(in) :: bathyP !< The pressure at the bathymetry [R L2 T-2 ~> Pa]
1424 real, dimension(SZI_(HI),SZJ_(HI)), &
1425 optional, intent(in) :: P_surf !< The pressure at the ocean surface [R L2 T-2 ~> Pa]
1426 real, optional, intent(in) :: dP_neglect !< A minuscule pressure change with
1427 !! the same units as p_t [R L2 T-2 ~> Pa]
1428 integer, optional, intent(in) :: MassWghtInterp !< A flag indicating whether and how to use
1429 !! mass weighting to interpolate T/S in integrals
1430 logical, optional, intent(in) :: MassWghtInterpVanOnly !< If true, does not do mass weighting
1431 !! of T/S unless one side smaller than h_nv (i.e. vanished)
1432 real, optional, intent(in) :: p_nv !< Nonvanished pressure [R L2 T-2 ~> Pa]
1433
1434! This subroutine calculates analytical and nearly-analytical integrals in
1435! pressure across layers of geopotential anomalies, which are required for
1436! calculating the finite-volume form pressure accelerations in a non-Boussinesq
1437! model. There are essentially no free assumptions, apart from the use of
1438! Boole's rule to do the horizontal integrals, and from a truncation in the
1439! series for log(1-eps/1+eps) that assumes that |eps| < 0.34.
1440
1441 ! Local variables
14420 real :: T5((5*HI%isd+1):(5*(HI%ied+2))) ! Temperatures along a line of subgrid locations [C ~> degC]
14430 real :: S5((5*HI%isd+1):(5*(HI%ied+2))) ! Salinities along a line of subgrid locations [S ~> ppt]
14440 real :: p5((5*HI%isd+1):(5*(HI%ied+2))) ! Pressures along a line of subgrid locations [R L2 T-2 ~> Pa]
14450 real :: a5((5*HI%isd+1):(5*(HI%ied+2))) ! Specific volumes anomalies along a line of subgrid
1446 ! locations [R-1 ~> m3 kg-1]
14470 real :: T15((15*HI%isd+1):(15*(HI%ied+1))) ! Temperatures at an array of subgrid locations [C ~> degC]
14480 real :: S15((15*HI%isd+1):(15*(HI%ied+1))) ! Salinities at an array of subgrid locations [S ~> ppt]
14490 real :: p15((15*HI%isd+1):(15*(HI%ied+1))) ! Pressures at an array of subgrid locations [R L2 T-2 ~> Pa]
14500 real :: a15((15*HI%isd+1):(15*(HI%ied+1))) ! Specific volumes at an array of subgrid locations [R ~> kg m-3]
1451 real :: alpha_anom ! The depth averaged specific density anomaly [R-1 ~> m3 kg-1]
1452 real :: dp ! The pressure change through a layer [R L2 T-2 ~> Pa]
14530 real :: dp_x(5,SZIB_(HI)) ! The pressure change through a layer along an x-line of subgrid locations [Z ~> m]
14540 real :: dp_y(5,SZI_(HI)) ! The pressure change through a layer along a y-line of subgrid locations [Z ~> m]
1455 real :: hWght ! A pressure-thickness below topography [R L2 T-2 ~> Pa]
1456 real :: hL, hR ! Pressure-thicknesses of the columns to the left and right [R L2 T-2 ~> Pa]
1457 real :: iDenom ! The inverse of the denominator in the weights [T4 R-2 L-4 ~> Pa-2]
1458 real :: hWt_LL, hWt_LR ! hWt_LA is the weighted influence of A on the left column [nondim]
1459 real :: hWt_RL, hWt_RR ! hWt_RA is the weighted influence of A on the right column [nondim]
1460 real :: wt_L, wt_R ! The linear weights of the left and right columns [nondim]
1461 real :: wtT_L, wtT_R ! The weights for tracers from the left and right columns [nondim]
1462 real :: intp(5) ! The integrals of specific volume with pressure at the
1463 ! 5 sub-column locations [L2 T-2 ~> m2 s-2]
1464 logical :: do_massWeight ! Indicates whether to do mass weighting.
1465 logical :: top_massWeight ! Indicates whether to do mass weighting the sea surface
1466 logical :: massWeight_bug ! If true, use an incorrect expression to determine where to apply mass weighting
1467 real :: massWeightNVonlyToggle ! A non-dimensional toggle factor for only using mass weighting
1468 ! if at least one side vanished (0 or 1) [nondim]
1469 real :: p_nonvanished ! nonvanished pressure [R L2 T-2 ~> Pa]
1470 real, parameter :: C1_90 = 1.0/90.0 ! A rational constant [nondim]
1471 integer, dimension(2) :: EOSdom_h5 ! The 5-point h-point i-computational domain for the equation of state
1472 integer, dimension(2) :: EOSdom_q15 ! The 3x5-point q-point i-computational domain for the equation of state
1473 integer, dimension(2) :: EOSdom_h15 ! The 3x5-point h-point i-computational domain for the equation of state
1474 integer :: Isq, Ieq, Jsq, Jeq, ish, ieh, jsh, jeh, i, j, m, n, pos, halo
1475
14760 Isq = HI%IscB ; Ieq = HI%IecB ; Jsq = HI%JscB ; Jeq = HI%JecB
14770 halo = 0 ; if (present(halo_size)) halo = MAX(halo_size,0)
14780 ish = HI%isc-halo ; ieh = HI%iec+halo ; jsh = HI%jsc-halo ; jeh = HI%jec+halo
14790 if (present(intx_dza)) then ; ish = MIN(Isq,ish) ; ieh = MAX(Ieq+1,ieh) ; endif
14800 if (present(inty_dza)) then ; jsh = MIN(Jsq,jsh) ; jeh = MAX(Jeq+1,jeh) ; endif
1481
14820 do_massWeight = .false. ; massWeight_bug = .false. ; top_massWeight = .false.
14830 if (present(MassWghtInterp)) then
14840 do_massWeight = BTEST(MassWghtInterp, 0) ! True for odd values
14850 top_massWeight = BTEST(MassWghtInterp, 1) ! True if the 2 bit is set
14860 massWeight_bug = BTEST(MassWghtInterp, 3) ! True if the 8 bit is set
14870 if (do_massWeight .and. .not.present(bathyP)) call MOM_error(FATAL, &
14880 "int_spec_vol_dp_generic_pcm: bathyP must be present if near-bottom mass weighting is in use.")
14890 if (top_massWeight .and. .not.present(P_surf)) call MOM_error(FATAL, &
14900 "int_spec_vol_dp_generic_pcm: P_surf must be present if near-surface mass weighting is in use.")
14910 if ((do_massWeight .or. top_massWeight) .and. .not.present(dP_neglect)) call MOM_error(FATAL, &
14920 "int_spec_vol_dp_generic_pcm: dP_neglect must be present if mass weighting is in use.")
1493 endif
14940 massWeightNVonlyToggle = 1.
14950 if (present(MassWghtInterpVanOnly)) then
14960 if (MassWghtInterpVanOnly) massWeightNVonlyToggle = 0.
1497 endif
14980 p_nonvanished = 0.
14990 if (present(p_nv)) then
15000 p_nonvanished = p_nv
1501 endif
1502
1503
1504 ! Set the loop ranges for equation of state calculations at various points.
15050 EOSdom_h5(1) = 1 ; EOSdom_h5(2) = 5*(ieh-ish+1)
15060 EOSdom_q15(1) = 1 ; EOSdom_q15(2) = 15*(Ieq-Isq+1)
15070 EOSdom_h15(1) = 1 ; EOSdom_h15(2) = 15*(HI%iec-HI%isc+1)
1508
15090 do j=jsh,jeh
15100 do i=ish,ieh
15110 dp = p_b(i,j) - p_t(i,j)
15120 pos = 5*i
15130 do n=1,5
15140 T5(pos+n) = T(i,j) ; S5(pos+n) = S(i,j)
15150 p5(pos+n) = p_b(i,j) - 0.25*real(n-1)*dp
1516 enddo
1517 enddo
1518
1519 call calculate_spec_vol(T5(5*ish+1:), S5(5*ish+1:), p5(5*ish+1:), a5(5*ish+1:), EOS, &
15200 EOSdom_h5, spv_ref=alpha_ref)
1521
15220 do i=ish,ieh
15230 dp = p_b(i,j) - p_t(i,j)
1524 ! Use Boole's rule to estimate the interface height anomaly change.
15250 pos = 5*i
15260 alpha_anom = C1_90*(7.0*(a5(pos+1)+a5(pos+5)) + 32.0*(a5(pos+2)+a5(pos+4)) + 12.0*a5(pos+3))
15270 dza(i,j) = dp*alpha_anom
1528 ! Use a Boole's-rule-like fifth-order accurate estimate of the double integral of
1529 ! the interface height anomaly.
15300 if (present(intp_dza)) intp_dza(i,j) = 0.5*dp**2 * &
15310 (alpha_anom - C1_90*(16.0*(a5(pos+4)-a5(pos+2)) + 7.0*(a5(pos+5)-a5(pos+1))) )
1532 enddo
1533 enddo
1534
15350 if (present(intx_dza)) then ; do j=HI%jsc,HI%jec
15360 do I=Isq,Ieq
1537 ! hWght is the distance measure by which the cell is violation of
1538 ! hydrostatic consistency. For large hWght we bias the interpolation of
1539 ! T & S along the top and bottom integrals, akin to thickness weighting.
15400 hWght = 0.0
15410 if (do_massWeight .and. massWeight_bug) then
15420 hWght = max(0., bathyP(i,j)-p_t(i+1,j), bathyP(i+1,j)-p_t(i,j))
15430 elseif (do_massWeight) then
15440 hWght = max(0., p_t(i+1,j)-bathyP(i,j), p_t(i,j)-bathyP(i+1,j))
1545 endif
15460 if (top_massWeight) &
15470 hWght = max(hWght, P_surf(i,j)-p_b(i+1,j), P_surf(i+1,j)-p_b(i,j))
1548 ! If both sides are nonvanished, then set it back to zero.
15490 if (((p_b(i,j) - p_t(i,j)) > p_nonvanished) .and. ((p_b(i+1,j) - p_t(i+1,j)) > p_nonvanished)) then
15500 hWght = massWeightNVonlyToggle * hWght
1551 endif
1552
15530 if (hWght > 0.) then
15540 hL = (p_b(i,j) - p_t(i,j)) + dP_neglect
15550 hR = (p_b(i+1,j) - p_t(i+1,j)) + dP_neglect
15560 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
15570 iDenom = 1.0 / ( hWght*(hR + hL) + hL*hR )
15580 hWt_LL = (hWght*hL + hR*hL) * iDenom ; hWt_LR = (hWght*hR) * iDenom
15590 hWt_RR = (hWght*hR + hR*hL) * iDenom ; hWt_RL = (hWght*hL) * iDenom
1560 else
15610 hWt_LL = 1.0 ; hWt_LR = 0.0 ; hWt_RR = 1.0 ; hWt_RL = 0.0
1562 endif
1563
15640 do m=2,4
15650 wt_L = 0.25*real(5-m) ; wt_R = 1.0-wt_L
15660 wtT_L = (wt_L*hWt_LL) + (wt_R*hWt_RL) ; wtT_R = (wt_L*hWt_LR) + (wt_R*hWt_RR)
15670 pos = i*15+(m-2)*5
1568
1569 ! T, S, and p are interpolated in the horizontal. The p interpolation
1570 ! is linear, but for T and S it may be thickness weighted.
15710 p15(pos+1) = (wt_L*p_b(i,j)) + (wt_R*p_b(i+1,j))
15720 dp_x(m,I) = (wt_L*(p_b(i,j) - p_t(i,j))) + (wt_R*(p_b(i+1,j) - p_t(i+1,j)))
15730 T15(pos+1) = (wtT_L*T(i,j)) + (wtT_R*T(i+1,j))
15740 S15(pos+1) = (wtT_L*S(i,j)) + (wtT_R*S(i+1,j))
1575
15760 do n=2,5
15770 T15(pos+n) = T15(pos+1) ; S15(pos+n) = S15(pos+1)
15780 p15(pos+n) = p15(pos+n-1) - 0.25*dp_x(m,I)
1579 enddo
1580 enddo
1581 enddo
1582
1583 call calculate_spec_vol(T15(15*Isq+1:), S15(15*Isq+1:), p15(15*Isq+1:), &
15840 a15(15*Isq+1:), EOS, EOSdom_q15, spv_ref=alpha_ref)
1585
15860 do I=Isq,Ieq
15870 intp(1) = dza(i,j) ; intp(5) = dza(i+1,j)
1588 ! Use Boole's rule to estimate the interface height anomaly change.
15890 do m=2,4
15900 pos = i*15+(m-2)*5
1591 intp(m) = (dp_x(m,I)*( C1_90*(7.0*(a15(pos+1)+a15(pos+5)) + 32.0*(a15(pos+2)+a15(pos+4)) + &
15920 12.0*a15(pos+3)) ))
1593 enddo
1594 ! Use Boole's rule to integrate the interface height anomaly values in x.
1595 intx_dza(i,j) = C1_90*(7.0*(intp(1)+intp(5)) + 32.0*(intp(2)+intp(4)) + &
15960 12.0*intp(3))
1597 enddo
1598 enddo ; endif
1599
16000 if (present(inty_dza)) then ; do J=Jsq,Jeq
16010 do i=HI%isc,HI%iec
1602 ! hWght is the distance measure by which the cell is violation of
1603 ! hydrostatic consistency. For large hWght we bias the interpolation of
1604 ! T & S along the top and bottom integrals, akin to thickness weighting.
16050 hWght = 0.0
16060 if (do_massWeight .and. massWeight_bug) then
16070 hWght = max(0., bathyP(i,j)-p_t(i,j+1), bathyP(i,j+1)-p_t(i,j))
16080 elseif (do_massWeight) then
16090 hWght = max(0., p_t(i,j+1)-bathyP(i,j), p_t(i,j)-bathyP(i,j+1))
1610 endif
16110 if (top_massWeight) &
16120 hWght = max(hWght, P_surf(i,j)-p_b(i,j+1), P_surf(i,j+1)-p_b(i,j))
1613 ! If both sides are nonvanished, then set it back to zero.
16140 if (((p_b(i,j) - p_t(i,j)) > p_nonvanished) .and. ((p_b(i,j+1) - p_t(i,j+1)) > p_nonvanished)) then
16150 hWght = massWeightNVonlyToggle * hWght
1616 endif
16170 if (hWght > 0.) then
16180 hL = (p_b(i,j) - p_t(i,j)) + dP_neglect
16190 hR = (p_b(i,j+1) - p_t(i,j+1)) + dP_neglect
16200 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
16210 iDenom = 1.0 / ( hWght*(hR + hL) + hL*hR )
16220 hWt_LL = (hWght*hL + hR*hL) * iDenom ; hWt_LR = (hWght*hR) * iDenom
16230 hWt_RR = (hWght*hR + hR*hL) * iDenom ; hWt_RL = (hWght*hL) * iDenom
1624 else
16250 hWt_LL = 1.0 ; hWt_LR = 0.0 ; hWt_RR = 1.0 ; hWt_RL = 0.0
1626 endif
1627
16280 do m=2,4
16290 wt_L = 0.25*real(5-m) ; wt_R = 1.0-wt_L
16300 wtT_L = (wt_L*hWt_LL) + (wt_R*hWt_RL) ; wtT_R = (wt_L*hWt_LR) + (wt_R*hWt_RR)
16310 pos = i*15+(m-2)*5
1632
1633 ! T, S, and p are interpolated in the horizontal. The p interpolation
1634 ! is linear, but for T and S it may be thickness weighted.
16350 p15(pos+1) = (wt_L*p_b(i,j)) + (wt_R*p_b(i,j+1))
16360 dp_y(m,i) = (wt_L*(p_b(i,j) - p_t(i,j))) + (wt_R*(p_b(i,j+1) - p_t(i,j+1)))
16370 T15(pos+1) = (wtT_L*T(i,j)) + (wtT_R*T(i,j+1))
16380 S15(pos+1) = (wtT_L*S(i,j)) + (wtT_R*S(i,j+1))
16390 do n=2,5
16400 T15(pos+n) = T15(pos+1) ; S15(pos+n) = S15(pos+1)
16410 p15(pos+n) = p15(pos+n-1) - 0.25*dp_y(m,i)
1642 enddo
1643 enddo
1644 enddo
1645
1646 call calculate_spec_vol(T15(15*HI%isc+1:), S15(15*HI%isc+1:), p15(15*HI%isc+1:), &
16470 a15(15*HI%isc+1:), EOS, EOSdom_h15, spv_ref=alpha_ref)
1648
16490 do i=HI%isc,HI%iec
1650
16510 intp(1) = dza(i,j) ; intp(5) = dza(i,j+1)
1652 ! Use Boole's rule to estimate the interface height anomaly change.
16530 do m=2,4
16540 pos = i*15+(m-2)*5
1655 intp(m) = (dp_y(m,i)*( C1_90*(7.0*(a15(pos+1)+a15(pos+5)) + 32.0*(a15(pos+2)+a15(pos+4)) + &
16560 12.0*a15(pos+3)) ))
1657 enddo
1658 ! Use Boole's rule to integrate the interface height anomaly values in y.
1659 inty_dza(i,j) = C1_90*(7.0*(intp(1)+intp(5)) + 32.0*(intp(2)+intp(4)) + &
16600 12.0*intp(3))
1661 enddo
1662 enddo ; endif
1663
16640end subroutine int_spec_vol_dp_generic_pcm
1665
1666!> This subroutine calculates integrals of specific volume anomalies in
1667!! pressure across layers, which are required for calculating the finite-volume
1668!! form pressure accelerations in a non-Boussinesq model. There are essentially
1669!! no free assumptions, apart from the use of Boole's rule quadrature to do the integrals.
16700subroutine int_spec_vol_dp_generic_plm(T_t, T_b, S_t, S_b, p_t, p_b, alpha_ref, &
16710 dP_neglect, bathyP, HI, EOS, US, dza, &
16720 intp_dza, intx_dza, inty_dza, P_surf, MassWghtInterp, &
1673 MassWghtInterpVanOnly, p_nv)
1674 type(hor_index_type), intent(in) :: HI !< A horizontal index type structure.
1675 real, dimension(SZI_(HI),SZJ_(HI)), &
1676 intent(in) :: T_t !< Potential temperature at the top of the layer [C ~> degC]
1677 real, dimension(SZI_(HI),SZJ_(HI)), &
1678 intent(in) :: T_b !< Potential temperature at the bottom of the layer [C ~> degC]
1679 real, dimension(SZI_(HI),SZJ_(HI)), &
1680 intent(in) :: S_t !< Salinity at the top the layer [S ~> ppt]
1681 real, dimension(SZI_(HI),SZJ_(HI)), &
1682 intent(in) :: S_b !< Salinity at the bottom the layer [S ~> ppt]
1683 real, dimension(SZI_(HI),SZJ_(HI)), &
1684 intent(in) :: p_t !< Pressure atop the layer [R L2 T-2 ~> Pa]
1685 real, dimension(SZI_(HI),SZJ_(HI)), &
1686 intent(in) :: p_b !< Pressure below the layer [R L2 T-2 ~> Pa]
1687 real, intent(in) :: alpha_ref !< A mean specific volume that is subtracted out
1688 !! to reduce the magnitude of each of the integrals [R-1 ~> m3 kg-1]
1689 !! The calculation is mathematically identical with different values of
1690 !! alpha_ref, but alpha_ref alters the effects of roundoff, and
1691 !! answers do change.
1692 real, intent(in) :: dP_neglect !<!< A miniscule pressure change with
1693 !! the same units as p_t [R L2 T-2 ~> Pa]
1694 real, dimension(SZI_(HI),SZJ_(HI)), &
1695 intent(in) :: bathyP !< The pressure at the bathymetry [R L2 T-2 ~> Pa]
1696 type(EOS_type), intent(in) :: EOS !< Equation of state structure
1697 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1698 real, dimension(SZI_(HI),SZJ_(HI)), &
1699 intent(inout) :: dza !< The change in the geopotential anomaly
1700 !! across the layer [L2 T-2 ~> m2 s-2]
1701 real, dimension(SZI_(HI),SZJ_(HI)), &
1702 optional, intent(inout) :: intp_dza !< The integral in pressure through the layer of
1703 !! the geopotential anomaly relative to the anomaly at the bottom of the
1704 !! layer [R L4 T-4 ~> Pa m2 s-2]
1705 real, dimension(SZIB_(HI),SZJ_(HI)), &
1706 optional, intent(inout) :: intx_dza !< The integral in x of the difference between
1707 !! the geopotential anomaly at the top and bottom of the layer divided
1708 !! by the x grid spacing [L2 T-2 ~> m2 s-2]
1709 real, dimension(SZI_(HI),SZJB_(HI)), &
1710 optional, intent(inout) :: inty_dza !< The integral in y of the difference between
1711 !! the geopotential anomaly at the top and bottom of the layer divided
1712 !! by the y grid spacing [L2 T-2 ~> m2 s-2]
1713 real, dimension(SZI_(HI),SZJ_(HI)), &
1714 optional, intent(in) :: P_surf !< The pressure at the ocean surface [R L2 T-2 ~> Pa]
1715 integer, optional, intent(in) :: MassWghtInterp !< A flag indicating whether and how to use
1716 !! mass weighting to interpolate T/S in integrals
1717 logical, optional, intent(in) :: MassWghtInterpVanOnly !< If true, does not do mass weighting
1718 !! of T/S unless one side smaller than h_nv (i.e. vanished)
1719 real, optional, intent(in) :: p_nv !< Nonvanished pressure [R L2 T-2 ~> Pa]
1720
1721! This subroutine calculates analytical and nearly-analytical integrals in
1722! pressure across layers of geopotential anomalies, which are required for
1723! calculating the finite-volume form pressure accelerations in a non-Boussinesq
1724! model. There are essentially no free assumptions, apart from the use of
1725! Boole's rule to do the horizontal integrals, and from a truncation in the
1726! series for log(1-eps/1+eps) that assumes that |eps| < 0.34.
1727
17280 real :: T5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Temperatures along a line of subgrid locations [C ~> degC]
17290 real :: S5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Salinities along a line of subgrid locations [S ~> ppt]
17300 real :: p5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Pressures along a line of subgrid locations [R L2 T-2 ~> Pa]
17310 real :: a5((5*HI%iscB+1):(5*(HI%iecB+2))) ! Specific volumes anomalies along a line of subgrid
1732 ! locations [R-1 ~> m3 kg-1]
17330 real :: T15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Temperatures at an array of subgrid locations [C ~> degC]
17340 real :: S15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Salinities at an array of subgrid locations [S ~> ppt]
17350 real :: p15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Pressures at an array of subgrid locations [R L2 T-2 ~> Pa]
17360 real :: a15((15*HI%iscB+1):(15*(HI%iecB+1))) ! Specific volumes at an array of subgrid locations [R ~> kg m-3]
1737 real :: wt_t(5), wt_b(5) ! Weights of top and bottom values at quadrature points [nondim]
1738 real :: T_top, T_bot ! Horizontally interpolated temperature at the cell top and bottom [C ~> degC]
1739 real :: S_top, S_bot ! Horizontally interpolated salinity at the cell top and bottom [S ~> ppt]
1740 real :: P_top, P_bot ! Horizontally interpolated pressure at the cell top and bottom [R L2 T-2 ~> Pa]
1741
1742 real :: alpha_anom ! The depth averaged specific density anomaly [R-1 ~> m3 kg-1]
1743 real :: dp ! The pressure change through a layer [R L2 T-2 ~> Pa]
17440 real :: dp_90(2:4,SZIB_(HI)) ! The pressure change through a layer divided by 90 [R L2 T-2 ~> Pa]
1745 real :: hWght ! A pressure-thickness below topography [R L2 T-2 ~> Pa]
1746 real :: hL, hR ! Pressure-thicknesses of the columns to the left and right [R L2 T-2 ~> Pa]
1747 real :: iDenom ! The inverse of the denominator in the weights [T4 R-2 L-4 ~> Pa-2]
1748 real :: hWt_LL, hWt_LR ! hWt_LA is the weighted influence of A on the left column [nondim]
1749 real :: hWt_RL, hWt_RR ! hWt_RA is the weighted influence of A on the right column [nondim]
1750 real :: wt_L, wt_R ! The linear weights of the left and right columns [nondim]
1751 real :: wtT_L, wtT_R ! The weights for tracers from the left and right columns [nondim]
1752 real :: intp(5) ! The integrals of specific volume with pressure at the
1753 ! 5 sub-column locations [L2 T-2 ~> m2 s-2]
1754 real, parameter :: C1_90 = 1.0/90.0 ! A rational constant [nondim]
1755 logical :: do_massWeight ! Indicates whether to do mass weighting.
1756 logical :: top_massWeight ! Indicates whether to do mass weighting the sea surface
1757 logical :: massWeight_bug ! If true, use an incorrect expression to determine where to apply mass weighting
1758 real :: massWeightNVonlyToggle ! A non-dimensional toggle factor for only using mass weighting
1759 ! if at least one side vanished (0 or 1) [nondim]
1760 real :: p_nonvanished ! nonvanished pressure [R L2 T-2 ~> Pa]
1761 integer, dimension(2) :: EOSdom_h5 ! The 5-point h-point i-computational domain for the equation of state
1762 integer, dimension(2) :: EOSdom_q15 ! The 3x5-point q-point i-computational domain for the equation of state
1763 integer, dimension(2) :: EOSdom_h15 ! The 3x5-point h-point i-computational domain for the equation of state
1764 integer :: Isq, Ieq, Jsq, Jeq, i, j, m, n, pos
1765
17660 Isq = HI%IscB ; Ieq = HI%IecB ; Jsq = HI%JscB ; Jeq = HI%JecB
1767
17680 do_massWeight = .false. ; massWeight_bug = .false. ; top_massWeight = .false.
17690 if (present(MassWghtInterp)) then
17700 do_massWeight = BTEST(MassWghtInterp, 0) ! True for odd values
17710 top_massWeight = BTEST(MassWghtInterp, 1) ! True if the 2 bit is set
17720 massWeight_bug = BTEST(MassWghtInterp, 3) ! True if the 8 bit is set
17730 if (top_massWeight .and. .not.present(P_surf)) call MOM_error(FATAL, &
17740 "int_spec_vol_dp_generic_plm: P_surf must be present if near-surface mass weighting is in use.")
1775 endif
17760 massWeightNVonlyToggle = 1.
17770 if (present(MassWghtInterpVanOnly)) then
17780 if (MassWghtInterpVanOnly) massWeightNVonlyToggle = 0.
1779 endif
17800 p_nonvanished = 0.
17810 if (present(p_nv)) then
17820 p_nonvanished = p_nv
1783 endif
1784
17850 do n = 1, 5 ! Note that these are reversed from int_density_dz.
17860 wt_t(n) = 0.25 * real(n-1)
17870 wt_b(n) = 1.0 - wt_t(n)
1788 enddo
1789
1790 ! Set the loop ranges for equation of state calculations at various points.
17910 EOSdom_h5(1) = 1 ; EOSdom_h5(2) = 5*(Ieq-Isq+2)
17920 EOSdom_q15(1) = 1 ; EOSdom_q15(2) = 15*(Ieq-Isq+1)
17930 EOSdom_h15(1) = 1 ; EOSdom_h15(2) = 15*(HI%iec-HI%isc+1)
1794
1795 ! 1. Compute vertical integrals
17960 do j=Jsq,Jeq+1
17970 do i=Isq,Ieq+1
17980 do n=1,5 ! T, S and p are linearly interpolated in the vertical.
17990 p5(i*5+n) = wt_t(n) * p_t(i,j) + wt_b(n) * p_b(i,j)
18000 S5(i*5+n) = wt_t(n) * S_t(i,j) + wt_b(n) * S_b(i,j)
18010 T5(i*5+n) = wt_t(n) * T_t(i,j) + wt_b(n) * T_b(i,j)
1802 enddo
1803 enddo
18040 call calculate_spec_vol(T5, S5, p5, a5, EOS, EOSdom_h5, spv_ref=alpha_ref)
18050 do i=Isq,Ieq+1
1806 ! Use Boole's rule to estimate the interface height anomaly change.
18070 dp = p_b(i,j) - p_t(i,j)
18080 alpha_anom = C1_90*((7.0*(a5(i*5+1)+a5(i*5+5)) + 32.0*(a5(i*5+2)+a5(i*5+4))) + 12.0*a5(i*5+3))
18090 dza(i,j) = dp*alpha_anom
1810 ! Use a Boole's-rule-like fifth-order accurate estimate of the double integral of
1811 ! the interface height anomaly.
18120 if (present(intp_dza)) intp_dza(i,j) = 0.5*dp**2 * &
18130 (alpha_anom - C1_90*(16.0*(a5(i*5+4)-a5(i*5+2)) + 7.0*(a5(i*5+5)-a5(i*5+1))) )
1814 enddo
1815 enddo
1816
1817 ! 2. Compute horizontal integrals in the x direction
18180 if (present(intx_dza)) then ; do j=HI%jsc,HI%jec
18190 do I=Isq,Ieq
1820 ! hWght is the distance measure by which the cell is violation of
1821 ! hydrostatic consistency. For large hWght we bias the interpolation
1822 ! of T,S along the top and bottom integrals, almost like thickness
1823 ! weighting. Note: To work in terrain following coordinates we could
1824 ! offset this distance by the layer thickness to replicate other models.
18250 hWght = 0.0
18260 if (do_massWeight .and. massWeight_bug) then
18270 hWght = max(0., bathyP(i,j)-p_t(i+1,j), bathyP(i+1,j)-p_t(i,j))
18280 elseif (do_massWeight) then
18290 hWght = max(0., p_t(i+1,j)-bathyP(i,j), p_t(i,j)-bathyP(i+1,j))
1830 endif
18310 if (top_massWeight) &
18320 hWght = max(hWght, P_surf(i,j)-p_b(i+1,j), P_surf(i+1,j)-p_b(i,j))
1833 ! If both sides are nonvanished, then set it back to zero.
18340 if (((p_b(i,j) - p_t(i,j)) > p_nonvanished) .and. ((p_b(i+1,j) - p_t(i+1,j)) > p_nonvanished)) then
18350 hWght = massWeightNVonlyToggle * hWght
1836 endif
18370 if (hWght > 0.) then
18380 hL = (p_b(i,j) - p_t(i,j)) + dP_neglect
18390 hR = (p_b(i+1,j) - p_t(i+1,j)) + dP_neglect
18400 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
18410 iDenom = 1.0 / ( hWght*(hR + hL) + hL*hR )
18420 hWt_LL = (hWght*hL + hR*hL) * iDenom ; hWt_LR = (hWght*hR) * iDenom
18430 hWt_RR = (hWght*hR + hR*hL) * iDenom ; hWt_RL = (hWght*hL) * iDenom
1844 else
18450 hWt_LL = 1.0 ; hWt_LR = 0.0 ; hWt_RR = 1.0 ; hWt_RL = 0.0
1846 endif
1847
18480 do m=2,4
18490 wt_L = 0.25*real(5-m) ; wt_R = 1.0-wt_L
18500 wtT_L = (wt_L*hWt_LL) + (wt_R*hWt_RL) ; wtT_R = (wt_L*hWt_LR) + (wt_R*hWt_RR)
1851
1852 ! T, S, and p are interpolated in the horizontal. The p interpolation
1853 ! is linear, but for T and S it may be thickness weighted.
18540 P_top = (wt_L*p_t(i,j)) + (wt_R*p_t(i+1,j))
18550 P_bot = (wt_L*p_b(i,j)) + (wt_R*p_b(i+1,j))
18560 T_top = (wtT_L*T_t(i,j)) + (wtT_R*T_t(i+1,j))
18570 T_bot = (wtT_L*T_b(i,j)) + (wtT_R*T_b(i+1,j))
18580 S_top = (wtT_L*S_t(i,j)) + (wtT_R*S_t(i+1,j))
18590 S_bot = (wtT_L*S_b(i,j)) + (wtT_R*S_b(i+1,j))
18600 dp_90(m,I) = C1_90*(P_bot - P_top)
1861
1862 ! Salinity, temperature and pressure with linear interpolation in the vertical.
18630 pos = i*15+(m-2)*5
18640 do n=1,5
18650 p15(pos+n) = wt_t(n) * P_top + wt_b(n) * P_bot
18660 S15(pos+n) = wt_t(n) * S_top + wt_b(n) * S_bot
18670 T15(pos+n) = wt_t(n) * T_top + wt_b(n) * T_bot
1868 enddo
1869 enddo
1870 enddo
1871
18720 call calculate_spec_vol(T15, S15, p15, a15, EOS, EOSdom_q15, spv_ref=alpha_ref)
1873
18740 do I=Isq,Ieq
18750 intp(1) = dza(i,j) ; intp(5) = dza(i+1,j)
18760 do m=2,4
1877 ! Use Boole's rule to estimate the interface height anomaly change.
1878 ! The integrals at the ends of the segment are already known.
18790 pos = I*15+(m-2)*5
1880 intp(m) = (dp_90(m,I)*((7.0*(a15(pos+1)+a15(pos+5)) + &
18810 32.0*(a15(pos+2)+a15(pos+4))) + 12.0*a15(pos+3) ))
1882 enddo
1883 ! Use Boole's rule to integrate the interface height anomaly values in x.
1884 intx_dza(I,j) = C1_90*((7.0*(intp(1)+intp(5)) + 32.0*(intp(2)+intp(4))) + &
18850 12.0*intp(3))
1886 enddo
1887 enddo ; endif
1888
1889 ! 3. Compute horizontal integrals in the y direction
18900 if (present(inty_dza)) then ; do J=Jsq,Jeq
18910 do i=HI%isc,HI%iec
1892 ! hWght is the distance measure by which the cell is violation of
1893 ! hydrostatic consistency. For large hWght we bias the interpolation
1894 ! of T,S along the top and bottom integrals, like thickness weighting.
18950 hWght = 0.0
18960 if (do_massWeight .and. massWeight_bug) then
18970 hWght = max(0., bathyP(i,j)-p_t(i,j+1), bathyP(i,j+1)-p_t(i,j))
18980 elseif (do_massWeight) then
18990 hWght = max(0., p_t(i,j+1)-bathyP(i,j), p_t(i,j)-bathyP(i,j+1))
1900 endif
19010 if (top_massWeight) &
19020 hWght = max(hWght, P_surf(i,j)-p_b(i,j+1), P_surf(i,j+1)-p_b(i,j))
1903 ! If both sides are nonvanished, then set it back to zero.
19040 if (((p_b(i,j) - p_t(i,j)) > p_nonvanished) .and. ((p_b(i,j+1) - p_t(i,j+1)) > p_nonvanished)) then
19050 hWght = massWeightNVonlyToggle * hWght
1906 endif
19070 if (hWght > 0.) then
19080 hL = (p_b(i,j) - p_t(i,j)) + dP_neglect
19090 hR = (p_b(i,j+1) - p_t(i,j+1)) + dP_neglect
19100 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
19110 iDenom = 1.0 / ( hWght*(hR + hL) + hL*hR )
19120 hWt_LL = (hWght*hL + hR*hL) * iDenom ; hWt_LR = (hWght*hR) * iDenom
19130 hWt_RR = (hWght*hR + hR*hL) * iDenom ; hWt_RL = (hWght*hL) * iDenom
1914 else
19150 hWt_LL = 1.0 ; hWt_LR = 0.0 ; hWt_RR = 1.0 ; hWt_RL = 0.0
1916 endif
1917
19180 do m=2,4
19190 wt_L = 0.25*real(5-m) ; wt_R = 1.0-wt_L
19200 wtT_L = (wt_L*hWt_LL) + (wt_R*hWt_RL) ; wtT_R = (wt_L*hWt_LR) + (wt_R*hWt_RR)
1921
1922 ! T, S, and p are interpolated in the horizontal. The p interpolation
1923 ! is linear, but for T and S it may be thickness weighted.
19240 P_top = (wt_L*p_t(i,j)) + (wt_R*p_t(i,j+1))
19250 P_bot = (wt_L*p_b(i,j)) + (wt_R*p_b(i,j+1))
19260 T_top = (wtT_L*T_t(i,j)) + (wtT_R*T_t(i,j+1))
19270 T_bot = (wtT_L*T_b(i,j)) + (wtT_R*T_b(i,j+1))
19280 S_top = (wtT_L*S_t(i,j)) + (wtT_R*S_t(i,j+1))
19290 S_bot = (wtT_L*S_b(i,j)) + (wtT_R*S_b(i,j+1))
19300 dp_90(m,i) = C1_90*(P_bot - P_top)
1931
1932 ! Salinity, temperature and pressure with linear interpolation in the vertical.
19330 pos = i*15+(m-2)*5
19340 do n=1,5
19350 p15(pos+n) = wt_t(n) * P_top + wt_b(n) * P_bot
19360 S15(pos+n) = wt_t(n) * S_top + wt_b(n) * S_bot
19370 T15(pos+n) = wt_t(n) * T_top + wt_b(n) * T_bot
1938 enddo
1939 enddo
1940 enddo
1941
1942 call calculate_spec_vol(T15(15*HI%isc+1:), S15(15*HI%isc+1:), p15(15*HI%isc+1:), &
19430 a15(15*HI%isc+1:), EOS, EOSdom_h15, spv_ref=alpha_ref)
1944
19450 do i=HI%isc,HI%iec
19460 intp(1) = dza(i,j) ; intp(5) = dza(i,j+1)
19470 do m=2,4
1948 ! Use Boole's rule to estimate the interface height anomaly change.
1949 ! The integrals at the ends of the segment are already known.
19500 pos = i*15+(m-2)*5
1951 intp(m) = (dp_90(m,i) * ((7.0*(a15(pos+1)+a15(pos+5)) + &
19520 32.0*(a15(pos+2)+a15(pos+4))) + 12.0*a15(pos+3)))
1953 enddo
1954 ! Use Boole's rule to integrate the interface height anomaly values in x.
1955 inty_dza(i,J) = C1_90*((7.0*(intp(1)+intp(5)) + 32.0*(intp(2)+intp(4))) + &
19560 12.0*intp(3))
1957 enddo
1958 enddo ; endif
1959
19600end subroutine int_spec_vol_dp_generic_plm
1961
1962
1963!> Diagnose the fractional mass weighting in a layer that might be used with a Boussinesq calculation.
19640subroutine diagnose_mass_weight_Z(z_t, z_b, bathyT, SSH, dz_neglect, MassWghtInterp, HI, &
19650 MassWt_u, MassWt_v, MassWghtInterpVanOnly, h_nv)
1966 type(hor_index_type), intent(in) :: HI !< A horizontal index type structure.
1967 real, dimension(SZI_(HI),SZJ_(HI)), &
1968 intent(in) :: z_t !< Height at the top of the layer in depth units [Z ~> m]
1969 real, dimension(SZI_(HI),SZJ_(HI)), &
1970 intent(in) :: z_b !< Height at the bottom of the layer [Z ~> m]
1971 real, dimension(SZI_(HI),SZJ_(HI)), &
1972 intent(in) :: bathyT !< The depth of the bathymetry [Z ~> m]
1973 real, dimension(SZI_(HI),SZJ_(HI)), &
1974 intent(in) :: SSH !< The sea surface height [Z ~> m]
1975 real, intent(in) :: dz_neglect !< A minuscule thickness change [Z ~> m]
1976 integer, intent(in) :: MassWghtInterp !< A flag indicating whether and how to use
1977 !! mass weighting to interpolate T/S in integrals
1978 real, dimension(SZIB_(HI),SZJ_(HI)), &
1979 intent(inout) :: MassWt_u !< The fractional mass weighting at u-points [nondim]
1980 real, dimension(SZI_(HI),SZJB_(HI)), &
1981 intent(inout) :: MassWt_v !< The fractional mass weighting at v-points [nondim]
1982 logical, optional, intent(in) :: MassWghtInterpVanOnly !< If true, does not do mass weighting
1983 !! of T/S unless one side smaller than h_nv (i.e. vanished)
1984 real, optional, intent(in) :: h_nv !< Nonvanished height [Z ~> m]
1985
1986 ! Local variables
1987 real :: hWght ! A pressure-thickness below topography [Z ~> m]
1988 real :: hL, hR ! Pressure-thicknesses of the columns to the left and right [Z ~> m]
1989 real :: iDenom ! The inverse of the denominator in the weights [Z-2 ~> m-2]
1990 logical :: do_massWeight ! Indicates whether to do mass weighting near bathymetry
1991 logical :: top_massWeight ! Indicates whether to do mass weighting the sea surface
1992 real :: massWeightNVonlyToggle ! A non-dimensional toggle factor for only using mass weighting
1993 real :: h_nonvanished ! nonvanished height [Z ~> m]
1994 integer :: Isq, Ieq, Jsq, Jeq, i, j
1995
19960 Isq = HI%IscB ; Ieq = HI%IecB
19970 Jsq = HI%JscB ; Jeq = HI%JecB
1998
19990 do_massWeight = BTEST(MassWghtInterp, 0) ! True for odd values
20000 top_massWeight = BTEST(MassWghtInterp, 1) ! True if the 2 bit is set
20010 massWeightNVonlyToggle = 1.
20020 if (present(MassWghtInterpVanOnly)) then
20030 if (MassWghtInterpVanOnly) massWeightNVonlyToggle = 0.
2004 endif
20050 h_nonvanished = 0.
20060 if (present(h_nv)) then
20070 h_nonvanished = h_nv
2008 endif
2009
2010 ! Calculate MassWt_u
20110 do j=HI%jsc,HI%jec ; do I=Isq,Ieq
2012 ! hWght is the distance measure by which the cell is violation of
2013 ! hydrostatic consistency. For large hWght we bias the interpolation
2014 ! of T,S along the top and bottom integrals, like thickness weighting.
20150 hWght = 0.0
20160 if (do_massWeight) &
20170 hWght = max(0., -bathyT(i,j)-z_t(i+1,j), -bathyT(i+1,j)-z_t(i,j))
20180 if (top_massWeight) &
20190 hWght = max(hWght, z_b(i+1,j)-SSH(i,j), z_b(i,j)-SSH(i+1,j))
2020 ! If both sides are nonvanished, then set it back to zero.
20210 if (((z_t(i,j) - z_b(i,j)) > h_nonvanished) .and. ((z_t(i+1,j) - z_b(i+1,j)) > h_nonvanished)) then
20220 hWght = massWeightNVonlyToggle * hWght
2023 endif
20240 if (hWght > 0.) then
20250 hL = (z_t(i,j) - z_b(i,j)) + dz_neglect
20260 hR = (z_t(i+1,j) - z_b(i+1,j)) + dz_neglect
20270 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
20280 iDenom = 1.0 / ( hWght*(hR + hL) + hL*hR )
20290 MassWt_u(I,j) = (hWght*hR + hWght*hL) * iDenom
2030 else
20310 MassWt_u(I,j) = 0.0
2032 endif
2033 enddo ; enddo
2034
2035 ! Calculate MassWt_v
20360 do J=Jsq,Jeq ; do i=HI%isc,HI%iec
2037 ! hWght is the distance measure by which the cell is violation of
2038 ! hydrostatic consistency. For large hWght we bias the interpolation
2039 ! of T,S along the top and bottom integrals, like thickness weighting.
20400 hWght = 0.0
20410 if (do_massWeight) &
20420 hWght = max(0., -bathyT(i,j)-z_t(i,j+1), -bathyT(i,j+1)-z_t(i,j))
20430 if (top_massWeight) &
20440 hWght = max(hWght, z_b(i,j+1)-SSH(i,j), z_b(i,j)-SSH(i,j+1))
2045 ! If both sides are nonvanished, then set it back to zero.
20460 if (((z_t(i,j) - z_b(i,j)) > h_nonvanished) .and. ((z_t(i,j+1) - z_b(i,j+1)) > h_nonvanished)) then
20470 hWght = massWeightNVonlyToggle * hWght
2048 endif
20490 if (hWght > 0.) then
20500 hL = (z_t(i,j) - z_b(i,j)) + dz_neglect
20510 hR = (z_t(i,j+1) - z_b(i,j+1)) + dz_neglect
20520 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
20530 iDenom = 1.0 / ( hWght*(hR + hL) + hL*hR )
20540 MassWt_v(i,J) = (hWght*hR + hWght*hL) * iDenom
2055 else
20560 MassWt_v(i,J) = 0.0
2057 endif
2058 enddo ; enddo
2059
20600end subroutine diagnose_mass_weight_Z
2061
2062
2063!> Diagnose the fractional mass weighting in a layer that might be used with a non-Boussinesq calculation.
20640subroutine diagnose_mass_weight_p(p_t, p_b, bathyP, P_surf, dP_neglect, MassWghtInterp, HI, &
20650 MassWt_u, MassWt_v, MassWghtInterpVanOnly, p_nv)
2066 type(hor_index_type), intent(in) :: HI !< A horizontal index type structure.
2067 real, dimension(SZI_(HI),SZJ_(HI)), &
2068 intent(in) :: p_t !< Pressure atop the layer [R L2 T-2 ~> Pa]
2069 real, dimension(SZI_(HI),SZJ_(HI)), &
2070 intent(in) :: p_b !< Pressure below the layer [R L2 T-2 ~> Pa]
2071 real, intent(in) :: dP_neglect !<!< A miniscule pressure change with
2072 !! the same units as p_t [R L2 T-2 ~> Pa]
2073 real, dimension(SZI_(HI),SZJ_(HI)), &
2074 intent(in) :: bathyP !< The pressure at the bathymetry [R L2 T-2 ~> Pa]
2075 real, dimension(SZI_(HI),SZJ_(HI)), &
2076 intent(in) :: P_surf !< The pressure at the ocean surface [R L2 T-2 ~> Pa]
2077 integer, intent(in) :: MassWghtInterp !< A flag indicating whether and how to use
2078 !! mass weighting to interpolate T/S in integrals
2079 real, dimension(SZIB_(HI),SZJ_(HI)), &
2080 intent(inout) :: MassWt_u !< The fractional mass weighting at u-points [nondim]
2081 real, dimension(SZI_(HI),SZJB_(HI)), &
2082 intent(inout) :: MassWt_v !< The fractional mass weighting at v-points [nondim]
2083 logical, optional, intent(in) :: MassWghtInterpVanOnly !< If true, does not do mass weighting
2084 !! of T/S unless one side smaller than h_nv (i.e. vanished)
2085 real, optional, intent(in) :: p_nv !< Nonvanished pressure [R L2 T-2 ~> Pa]
2086
2087 ! Local variables
2088 real :: hWght ! A pressure-thickness below topography [R L2 T-2 ~> Pa]
2089 real :: hL, hR ! Pressure-thicknesses of the columns to the left and right [R L2 T-2 ~> Pa]
2090 real :: iDenom ! The inverse of the denominator in the weights [T4 R-2 L-4 ~> Pa-2]
2091 logical :: do_massWeight ! Indicates whether to do mass weighting.
2092 logical :: top_massWeight ! Indicates whether to do mass weighting the sea surface
2093 logical :: massWeight_bug ! If true, use an incorrect expression to determine where to apply mass weighting
2094 real :: massWeightNVonlyToggle ! A non-dimensional toggle factor for only using mass weighting
2095 ! if at least one side vanished (0 or 1) [nondim]
2096 real :: p_nonvanished ! nonvanished pressure [R L2 T-2 ~> Pa]
2097
2098 integer :: Isq, Ieq, Jsq, Jeq, i, j
2099
21000 Isq = HI%IscB ; Ieq = HI%IecB
21010 Jsq = HI%JscB ; Jeq = HI%JecB
2102
21030 do_massWeight = BTEST(MassWghtInterp, 0) ! True for odd values
21040 top_massWeight = BTEST(MassWghtInterp, 1) ! True if the 2 bit is set
21050 massWeight_bug = BTEST(MassWghtInterp, 3) ! True if the 8 bit is set
21060 massWeightNVonlyToggle = 1.
21070 if (present(MassWghtInterpVanOnly)) then
21080 if (MassWghtInterpVanOnly) massWeightNVonlyToggle = 0.
2109 endif
21100 p_nonvanished = 0.
21110 if (present(p_nv)) then
21120 p_nonvanished = p_nv
2113 endif
2114
2115 ! Calculate MassWt_u
21160 do j=HI%jsc,HI%jec ; do I=Isq,Ieq
2117 ! hWght is the distance measure by which the cell is violation of
2118 ! hydrostatic consistency. For large hWght we bias the interpolation
2119 ! of T,S along the top and bottom integrals, like thickness weighting.
21200 hWght = 0.0
21210 if (do_massWeight .and. massWeight_bug) then
21220 hWght = max(0., bathyP(i,j)-p_t(i+1,j), bathyP(i+1,j)-p_t(i,j))
21230 elseif (do_massWeight) then
21240 hWght = max(0., p_t(i+1,j)-bathyP(i,j), p_t(i,j)-bathyP(i+1,j))
2125 endif
21260 if (top_massWeight) &
21270 hWght = max(hWght, P_surf(i,j)-p_b(i+1,j), P_surf(i+1,j)-p_b(i,j))
2128 ! If both sides are nonvanished, then set it back to zero.
21290 if (((p_b(i,j) - p_t(i,j)) > p_nonvanished) .and. ((p_b(i+1,j) - p_t(i+1,j)) > p_nonvanished)) then
21300 hWght = massWeightNVonlyToggle * hWght
2131 endif
21320 if (hWght > 0.) then
21330 hL = (p_b(i,j) - p_t(i,j)) + dP_neglect
21340 hR = (p_b(i+1,j) - p_t(i+1,j)) + dP_neglect
21350 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
21360 iDenom = 1.0 / ( hWght*(hR + hL) + hL*hR )
21370 MassWt_u(I,j) = (hWght*hR + hWght*hL) * iDenom
2138 else
21390 MassWt_u(I,j) = 0.0
2140 endif
2141 enddo ; enddo
2142
2143 ! Calculate MassWt_v
21440 do J=Jsq,Jeq ; do i=HI%isc,HI%iec
2145 ! hWght is the distance measure by which the cell is violation of
2146 ! hydrostatic consistency. For large hWght we bias the interpolation
2147 ! of T,S along the top and bottom integrals, like thickness weighting.
21480 hWght = 0.0
21490 if (do_massWeight .and. massWeight_bug) then
21500 hWght = max(0., bathyP(i,j)-p_t(i,j+1), bathyP(i,j+1)-p_t(i,j))
21510 elseif (do_massWeight) then
21520 hWght = max(0., p_t(i,j+1)-bathyP(i,j), p_t(i,j)-bathyP(i,j+1))
2153 endif
21540 if (top_massWeight) &
21550 hWght = max(hWght, P_surf(i,j)-p_b(i,j+1), P_surf(i,j+1)-p_b(i,j))
2156 ! If both sides are nonvanished, then set it back to zero.
21570 if (((p_b(i,j) - p_t(i,j)) > p_nonvanished) .and. ((p_b(i,j+1) - p_t(i,j+1)) > p_nonvanished)) then
21580 hWght = massWeightNVonlyToggle * hWght
2159 endif
21600 if (hWght > 0.) then
21610 hL = (p_b(i,j) - p_t(i,j)) + dP_neglect
21620 hR = (p_b(i,j+1) - p_t(i,j+1)) + dP_neglect
21630 hWght = hWght * ( (hL-hR)/(hL+hR) )**2
21640 iDenom = 1.0 / ( hWght*(hR + hL) + hL*hR )
21650 MassWt_v(i,J) = (hWght*hR + hWght*hL) * iDenom
2166 else
21670 MassWt_v(i,J) = 0.0
2168 endif
2169 enddo ; enddo
2170
21710end subroutine diagnose_mass_weight_p
2172
2173!> Find the depth at which the reconstructed pressure matches P_tgt
21740subroutine find_depth_of_pressure_in_cell(T_t, T_b, S_t, S_b, z_t, z_b, P_t, P_tgt, &
2175 rho_ref, G_e, EOS, US, P_b, z_out, z_tol, frac_dp_bugfix)
2176 real, intent(in) :: T_t !< Potential temperature at the cell top [C ~> degC]
2177 real, intent(in) :: T_b !< Potential temperature at the cell bottom [C ~> degC]
2178 real, intent(in) :: S_t !< Salinity at the cell top [S ~> ppt]
2179 real, intent(in) :: S_b !< Salinity at the cell bottom [S ~> ppt]
2180 real, intent(in) :: z_t !< Absolute height of top of cell [Z ~> m] (Boussinesq ????)
2181 real, intent(in) :: z_b !< Absolute height of bottom of cell [Z ~> m]
2182 real, intent(in) :: P_t !< Anomalous pressure of top of cell, relative
2183 !! to g*rho_ref*z_t [R L2 T-2 ~> Pa]
2184 real, intent(in) :: P_tgt !< Target pressure at height z_out, relative
2185 !! to g*rho_ref*z_out [R L2 T-2 ~> Pa]
2186 real, intent(in) :: rho_ref !< Reference density with which calculation
2187 !! are anomalous to [R ~> kg m-3]
2188 real, intent(in) :: G_e !< Gravitational acceleration [L2 Z-1 T-2 ~> m s-2]
2189 type(EOS_type), intent(in) :: EOS !< Equation of state structure
2190 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2191 real, intent(out) :: P_b !< Pressure at the bottom of the cell [R L2 T-2 ~> Pa]
2192 real, intent(out) :: z_out !< Absolute depth at which anomalous pressure = p_tgt [Z ~> m]
2193 real, intent(in) :: z_tol !< The tolerance in finding z_out [Z ~> m]
2194 logical, intent(in) :: frac_dp_bugfix !< If true, use bugfix in frac_dp_at_pos
2195
2196 ! Local variables
2197 real :: dp ! Pressure thickness of the layer [R L2 T-2 ~> Pa]
2198 real :: F_guess, F_l, F_r ! Fractional positions [nondim]
2199 real :: GxRho ! The product of the gravitational acceleration and reference density [R L2 Z-1 T-2 ~> Pa m-1]
2200 real :: Pa, Pa_left, Pa_right, Pa_tol ! Pressure anomalies, P = integral of g*(rho-rho_ref) dz [R L2 T-2 ~> Pa]
2201 integer :: m ! A counter for how many iterations have been done in the while loop
2202 character(len=240) :: msg
2203
22040 GxRho = G_e * rho_ref
2205
2206 ! Anomalous pressure difference across whole cell
22070 dp = frac_dp_at_pos(T_t, T_b, S_t, S_b, z_t, z_b, rho_ref, G_e, 1.0, EOS, frac_dp_bugfix)
2208
22090 P_b = P_t + dp ! Anomalous pressure at bottom of cell
2210
22110 if (P_tgt <= P_t ) then
22120 z_out = z_t
22130 return
2214 endif
2215
22160 if (P_tgt >= P_b) then
22170 z_out = z_b
22180 return
2219 endif
2220
22210 F_l = 0.
22220 Pa_left = P_t - P_tgt ! Pa_left < 0
22230 F_r = 1.
22240 Pa_right = P_b - P_tgt ! Pa_right > 0
22250 Pa_tol = GxRho * z_tol
2226
22270 F_guess = F_l - Pa_left / (Pa_right - Pa_left) * (F_r - F_l)
22280 Pa = Pa_right - Pa_left ! To get into iterative loop
22290 m = 0 ! Reset the counter for the loop to be zero
22300 do while ( abs(Pa) > Pa_tol )
2231
22320 m = m + 1
22330 if (m > 30) then ! Call an error, because convergence to the tolerance has not been achieved
22340 write(msg,*) Pa_left,Pa,Pa_right,P_t-P_tgt,P_b-P_tgt
22350 call MOM_error(FATAL, 'find_depth_of_pressure_in_cell completes too many iterations: '//msg)
2236 endif
22370 z_out = z_t + ( z_b - z_t ) * F_guess
22380 Pa = frac_dp_at_pos(T_t, T_b, S_t, S_b, z_t, z_b, rho_ref, G_e, F_guess, EOS, frac_dp_bugfix) - ( P_tgt - P_t )
2239
22400 if (Pa<Pa_left) then
22410 write(msg,*) Pa_left,Pa,Pa_right,P_t-P_tgt,P_b-P_tgt
22420 call MOM_error(FATAL, 'find_depth_of_pressure_in_cell out of bounds negative: /n'//msg)
22430 elseif (Pa<0.) then
22440 Pa_left = Pa
22450 F_l = F_guess
22460 elseif (Pa>Pa_right) then
22470 write(msg,*) Pa_left,Pa,Pa_right,P_t-P_tgt,P_b-P_tgt
22480 call MOM_error(FATAL, 'find_depth_of_pressure_in_cell out of bounds positive: /n'//msg)
22490 elseif (Pa>0.) then
22500 Pa_right = Pa
22510 F_r = F_guess
2252 else ! Pa == 0
22530 return
2254 endif
22550 F_guess = F_l - Pa_left / (Pa_right - Pa_left) * (F_r - F_l)
2256
2257 enddo
2258
2259end subroutine find_depth_of_pressure_in_cell
2260
2261!> Calculate the average in situ specific volume across layers
22620subroutine avg_specific_vol(T, S, p_t, dp, HI, EOS, SpV_avg, halo_size)
2263 type(hor_index_type), intent(in) :: HI !< The horizontal index structure
2264 real, dimension(SZI_(HI),SZJ_(HI)), &
2265 intent(in) :: T !< Potential temperature of the layer [C ~> degC]
2266 real, dimension(SZI_(HI),SZJ_(HI)), &
2267 intent(in) :: S !< Salinity of the layer [S ~> ppt]
2268 real, dimension(SZI_(HI),SZJ_(HI)), &
2269 intent(in) :: p_t !< Pressure at the top of the layer [R L2 T-2 ~> Pa]
2270 real, dimension(SZI_(HI),SZJ_(HI)), &
2271 intent(in) :: dp !< Pressure change in the layer [R L2 T-2 ~> Pa]
2272 type(EOS_type), intent(in) :: EOS !< Equation of state structure
2273 real, dimension(SZI_(HI),SZJ_(HI)), &
2274 intent(inout) :: SpV_avg !< The vertical average specific volume
2275 !! in the layer [R-1 ~> m3 kg-1]
2276 integer, optional, intent(in) :: halo_size !< The number of halo points in which to work.
2277
2278 ! Local variables
2279 integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state
2280 integer :: jsh, jeh, j, halo
2281
22820 halo = 0 ; if (present(halo_size)) halo = MAX(halo_size,0)
22830 jsh = HI%jsc-halo ; jeh = HI%jec+halo
2284
22850 EOSdom(:) = EOS_domain(HI, halo_size)
22860 do j=jsh,jeh
22870 call average_specific_vol(T(:,j), S(:,j), p_t(:,j), dp(:,j), SpV_avg(:,j), EOS, EOSdom)
2288 enddo
2289
22900end subroutine avg_specific_vol
2291
2292!> Returns change in anomalous pressure change from top to non-dimensional
2293!! position pos between z_t and z_b [R L2 T-2 ~> Pa]
22940real function frac_dp_at_pos(T_t, T_b, S_t, S_b, z_t, z_b, rho_ref, G_e, pos, EOS, frac_dp_bugfix)
2295 real, intent(in) :: T_t !< Potential temperature at the cell top [C ~> degC]
2296 real, intent(in) :: T_b !< Potential temperature at the cell bottom [C ~> degC]
2297 real, intent(in) :: S_t !< Salinity at the cell top [S ~> ppt]
2298 real, intent(in) :: S_b !< Salinity at the cell bottom [S ~> ppt]
2299 real, intent(in) :: z_t !< The geometric height at the top of the layer [Z ~> m]
2300 real, intent(in) :: z_b !< The geometric height at the bottom of the layer [Z ~> m]
2301 real, intent(in) :: rho_ref !< A mean density [R ~> kg m-3], that is subtracted out to
2302 !! reduce the magnitude of each of the integrals.
2303 real, intent(in) :: G_e !< The Earth's gravitational acceleration [L2 Z-1 T-2 ~> m s-2]
2304 real, intent(in) :: pos !< The fractional vertical position, 0 to 1 [nondim]
2305 type(EOS_type), intent(in) :: EOS !< Equation of state structure
2306 logical, intent(in) :: frac_dp_bugfix !< If true, use bugfix in frac_dp_at_pos
2307
2308 ! Local variables
2309 real, parameter :: C1_90 = 1.0/90.0 ! A rational constant [nondim]
2310 real :: dz ! Distance from the layer top [Z ~> m]
2311 real :: top_weight, bottom_weight ! Fractional weights at quadrature points [nondim]
2312 real :: rho_ave ! Average density [R ~> kg m-3]
2313 real, dimension(5) :: T5 ! Temperatures at quadrature points [C ~> degC]
2314 real, dimension(5) :: S5 ! Salinities at quadrature points [S ~> ppt]
2315 real, dimension(5) :: p5 ! Pressures at quadrature points [R L2 T-2 ~> Pa]
2316 real, dimension(5) :: rho5 ! Densities at quadrature points [R ~> kg m-3]
2317 integer :: n
2318
23190 do n=1,5
2320 ! Evaluate density at five quadrature points
23210 bottom_weight = 0.25*real(n-1) * pos
23220 top_weight = 1.0 - bottom_weight
2323 ! Salinity and temperature points are linearly interpolated
23240 S5(n) = top_weight * S_t + bottom_weight * S_b
23250 T5(n) = top_weight * T_t + bottom_weight * T_b
23260 if (frac_dp_bugfix) then
23270 p5(n) = (-1) * ( top_weight * z_t + bottom_weight * z_b ) * ( G_e * rho_ref )
2328 else
23290 p5(n) = ( top_weight * z_t + bottom_weight * z_b ) * ( G_e * rho_ref )
2330 endif !bugfix
2331 enddo
23320 call calculate_density(T5, S5, p5, rho5, EOS)
23330 rho5(:) = rho5(:) !- rho_ref ! Work with anomalies relative to rho_ref
2334
2335 ! Use Boole's rule to estimate the average density
23360 rho_ave = C1_90*(7.0*(rho5(1)+rho5(5)) + 32.0*(rho5(2)+rho5(4)) + 12.0*rho5(3))
2337
23380 dz = ( z_t - z_b ) * pos
23390 frac_dp_at_pos = G_e * dz * rho_ave
23400end function frac_dp_at_pos
2341
2342end module MOM_density_integrals
2343
2344!> \namespace mom_density_integrals
2345!!