MOM6
MOM_EOS_Wright.F90
Go to the documentation of this file.
2 !***********************************************************************
3 !* GNU General Public License *
4 !* This file is a part of MOM. *
5 !* *
6 !* MOM is free software; you can redistribute it and/or modify it and *
7 !* are expected to follow the terms of the GNU General Public License *
8 !* as published by the Free Software Foundation; either version 2 of *
9 !* the License, or (at your option) any later version. *
10 !* *
11 !* MOM is distributed in the hope that it will be useful, but WITHOUT *
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
13 !* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public *
14 !* License for more details. *
15 !* *
16 !* For the full text of the GNU General Public License, *
17 !* write to: Free Software Foundation, Inc., *
18 !* 675 Mass Ave, Cambridge, MA 02139, USA. *
19 !* or see: http://www.gnu.org/licenses/gpl.html *
20 !***********************************************************************
21 
22 !***********************************************************************
23 !* The subroutines in this file implement the equation of state for *
24 !* sea water using the formulae given by Wright, 1997, J. Atmos. *
25 !* Ocean. Tech., 14, 735-740. Coded by R. Hallberg, 7/00. *
26 !***********************************************************************
27 
28 use mom_hor_index, only : hor_index_type
29 
30 implicit none ; private
31 
32 #include <MOM_memory.h>
33 
38 
41 end interface calculate_density_wright
42 
43 !real :: a0, a1, a2, b0, b1, b2, b3, b4, b5, c0, c1, c2, c3, c4, c5
44 ! One of the two following blocks of values should be commented out.
45 ! Following are the values for the full range formula.
46 !
47 !real, parameter :: a0 = 7.133718e-4, a1 = 2.724670e-7, a2 = -1.646582e-7
48 !real, parameter :: b0 = 5.613770e8, b1 = 3.600337e6, b2 = -3.727194e4
49 !real, parameter :: b3 = 1.660557e2, b4 = 6.844158e5, b5 = -8.389457e3
50 !real, parameter :: c0 = 1.609893e5, c1 = 8.427815e2, c2 = -6.931554
51 !real, parameter :: c3 = 3.869318e-2, c4 = -1.664201e2, c5 = -2.765195
52 
53 
54 ! Following are the values for the reduced range formula.
55 real, parameter :: a0 = 7.057924e-4, a1 = 3.480336e-7, a2 = -1.112733e-7
56 real, parameter :: b0 = 5.790749e8, b1 = 3.516535e6, b2 = -4.002714e4
57 real, parameter :: b3 = 2.084372e2, b4 = 5.944068e5, b5 = -9.643486e3
58 real, parameter :: c0 = 1.704853e5, c1 = 7.904722e2, c2 = -7.984422
59 real, parameter :: c3 = 5.140652e-2, c4 = -2.302158e2, c5 = -3.079464
60 
61 contains
62 
63 !> This subroutine computes the in situ density of sea water (rho in
64 !! units of kg/m^3) from salinity (S in psu), potential temperature
65 !! (T in deg C), and pressure in Pa. It uses the expression from
66 !! Wright, 1997, J. Atmos. Ocean. Tech., 14, 735-740.
67 !! Coded by R. Hallberg, 7/00
68 subroutine calculate_density_scalar_wright(T, S, pressure, rho)
69 real, intent(in) :: T !< Potential temperature relative to the surface in C.
70 real, intent(in) :: S !< Salinity in PSU.
71 real, intent(in) :: pressure !< Pressure in Pa.
72 real, intent(out) :: rho !< In situ density in kg m-3.
73 
74 ! * Arguments: T - potential temperature relative to the surface in C. *
75 ! * (in) S - salinity in PSU. *
76 ! * (in) pressure - pressure in Pa. *
77 ! * (out) rho - in situ density in kg m-3. *
78 ! * (in) start - the starting point in the arrays. *
79 ! * (in) npts - the number of values to calculate. *
80 
81 ! *====================================================================*
82 ! * This subroutine computes the in situ density of sea water (rho in *
83 ! * units of kg/m^3) from salinity (S in psu), potential temperature *
84 ! * (T in deg C), and pressure in Pa. It uses the expression from *
85 ! * Wright, 1997, J. Atmos. Ocean. Tech., 14, 735-740. *
86 ! * Coded by R. Hallberg, 7/00 *
87 ! *====================================================================*
88 
89  real :: al0, p0, lambda
90  integer :: j
91  real, dimension(1) :: T0, S0, pressure0
92  real, dimension(1) :: rho0
93 
94  t0(1) = t
95  s0(1) = s
96  pressure0(1) = pressure
97 
98  call calculate_density_array_wright(t0, s0, pressure0, rho0, 1, 1)
99  rho = rho0(1)
100 
101 end subroutine calculate_density_scalar_wright
102 
103 !> This subroutine computes the in situ density of sea water (rho in
104 !! units of kg/m^3) from salinity (S in psu), potential temperature
105 !! (T in deg C), and pressure in Pa. It uses the expression from
106 !! Wright, 1997, J. Atmos. Ocean. Tech., 14, 735-740.
107 !! Coded by R. Hallberg, 7/00
108 subroutine calculate_density_array_wright(T, S, pressure, rho, start, npts)
109  real, intent(in), dimension(:) :: T !< potential temperature relative to the surface
110  !! in C.
111  real, intent(in), dimension(:) :: S !< salinity in PSU.
112  real, intent(in), dimension(:) :: pressure !< pressure in Pa.
113  real, intent(out), dimension(:) :: rho !< in situ density in kg m-3.
114  integer, intent(in) :: start !< the starting point in the arrays.
115  integer, intent(in) :: npts !< the number of values to calculate.
116 
117 ! * Arguments: T - potential temperature relative to the surface in C. *
118 ! * (in) S - salinity in PSU. *
119 ! * (in) pressure - pressure in Pa. *
120 ! * (out) rho - in situ density in kg m-3. *
121 ! * (in) start - the starting point in the arrays. *
122 ! * (in) npts - the number of values to calculate. *
123 
124 ! *====================================================================*
125 ! * This subroutine computes the in situ density of sea water (rho in *
126 ! * units of kg/m^3) from salinity (S in psu), potential temperature *
127 ! * (T in deg C), and pressure in Pa. It uses the expression from *
128 ! * Wright, 1997, J. Atmos. Ocean. Tech., 14, 735-740. *
129 ! * Coded by R. Hallberg, 7/00 *
130 ! *====================================================================*
131  real :: al0, p0, lambda
132  integer :: j
133 
134  do j=start,start+npts-1
135  al0 = (a0 + a1*t(j)) +a2*s(j)
136  p0 = (b0 + b4*s(j)) + t(j) * (b1 + t(j)*((b2 + b3*t(j))) + b5*s(j))
137  lambda = (c0 +c4*s(j)) + t(j) * (c1 + t(j)*((c2 + c3*t(j))) + c5*s(j))
138 
139  rho(j) = (pressure(j) + p0) / (lambda + al0*(pressure(j) + p0))
140  enddo
141 end subroutine calculate_density_array_wright
142 
143 ! #@# This subroutine needs a doxygen description.
144 subroutine calculate_density_derivs_wright(T, S, pressure, drho_dT, drho_dS, start, npts)
145  real, intent(in), dimension(:) :: T !< Potential temperature relative to the surface
146  !! in C.
147  real, intent(in), dimension(:) :: S !< Salinity in PSU.
148  real, intent(in), dimension(:) :: pressure !< Pressure in Pa.
149  real, intent(out), dimension(:) :: drho_dT !< The partial derivative of density with potential
150  !! temperature, in kg m-3 K-1.
151  real, intent(out), dimension(:) :: drho_dS !< The partial derivative of density with salinity,
152  !! in kg m-3 psu-1.
153  integer, intent(in) :: start !< The starting point in the arrays.
154  integer, intent(in) :: npts !< The number of values to calculate.
155 
156 ! * Arguments: T - potential temperature relative to the surface in C. *
157 ! * (in) S - salinity in PSU. *
158 ! * (in) pressure - pressure in Pa. *
159 ! * (out) drho_dT - the partial derivative of density with *
160 ! * potential temperature, in kg m-3 K-1. *
161 ! * (out) drho_dS - the partial derivative of density with *
162 ! * salinity, in kg m-3 psu-1. *
163 ! * (in) start - the starting point in the arrays. *
164 ! * (in) npts - the number of values to calculate. *
165  real :: al0, p0, lambda, I_denom2
166  integer :: j
167 
168  do j=start,start+npts-1
169  al0 = (a0 + a1*t(j)) + a2*s(j)
170  p0 = (b0 + b4*s(j)) + t(j) * (b1 + t(j)*((b2 + b3*t(j))) + b5*s(j))
171  lambda = (c0 +c4*s(j)) + t(j) * (c1 + t(j)*((c2 + c3*t(j))) + c5*s(j))
172 
173  i_denom2 = 1.0 / (lambda + al0*(pressure(j) + p0))
174  i_denom2 = i_denom2 *i_denom2
175  drho_dt(j) = i_denom2 * &
176  (lambda* (b1 + t(j)*(2.0*b2 + 3.0*b3*t(j)) + b5*s(j)) - &
177  (pressure(j)+p0) * ( (pressure(j)+p0)*a1 + &
178  (c1 + t(j)*(c2*2.0 + c3*3.0*t(j)) + c5*s(j)) ))
179  drho_ds(j) = i_denom2 * (lambda* (b4 + b5*t(j)) - &
180  (pressure(j)+p0) * ( (pressure(j)+p0)*a2 + (c4 + c5*t(j)) ))
181  enddo
182 
183 end subroutine calculate_density_derivs_wright
184 
185 subroutine calculate_specvol_derivs_wright(T, S, pressure, dSV_dT, dSV_dS, start, npts)
186  real, intent(in), dimension(:) :: T !< Potential temperature relative to the surface
187  !! in C.
188  real, intent(in), dimension(:) :: S !< Salinity in g/kg.
189  real, intent(in), dimension(:) :: pressure !< Pressure in Pa.
190  real, intent(out), dimension(:) :: dSV_dT !< The partial derivative of specific volume with
191  !! potential temperature, in m3 kg-1 K-1.
192  real, intent(out), dimension(:) :: dSV_dS !< The partial derivative of specific volume with
193  !! salinity, in m3 kg-1 / (g/kg).
194  integer, intent(in) :: start !< The starting point in the arrays.
195  integer, intent(in) :: npts !< The number of values to calculate.
196 
197 ! * Arguments: T - potential temperature relative to the surface in C. *
198 ! * (in) S - salinity in g/kg. *
199 ! * (in) pressure - pressure in Pa. *
200 ! * (out) dSV_dT - the partial derivative of specific volume with *
201 ! * potential temperature, in m3 kg-1 K-1. *
202 ! * (out) dSV_dS - the partial derivative of specific volume with *
203 ! * salinity, in m3 kg-1 / (g/kg). *
204 ! * (in) start - the starting point in the arrays. *
205 ! * (in) npts - the number of values to calculate. *
206  real :: al0, p0, lambda, I_denom
207  integer :: j
208 
209  do j=start,start+npts-1
210 ! al0 = (a0 + a1*T(j)) + a2*S(j)
211  p0 = (b0 + b4*s(j)) + t(j) * (b1 + t(j)*((b2 + b3*t(j))) + b5*s(j))
212  lambda = (c0 +c4*s(j)) + t(j) * (c1 + t(j)*((c2 + c3*t(j))) + c5*s(j))
213 
214  ! SV = al0 + lambda / (pressure(j) + p0)
215 
216  i_denom = 1.0 / (pressure(j) + p0)
217  dsv_dt(j) = (a1 + i_denom * (c1 + t(j)*((2.0*c2 + 3.0*c3*t(j))) + c5*s(j))) - &
218  (i_denom**2 * lambda) * (b1 + t(j)*((2.0*b2 + 3.0*b3*t(j))) + b5*s(j))
219  dsv_ds(j) = (a2 + i_denom * (c4 + c5*t(j))) - &
220  (i_denom**2 * lambda) * (b4 + b5*t(j))
221  enddo
222 
223 end subroutine calculate_specvol_derivs_wright
224 
225 !> This subroutine computes the in situ density of sea water (rho in
226 !! units of kg/m^3) and the compressibility (drho/dp = C_sound^-2)
227 !! (drho_dp in units of s2 m-2) from salinity (sal in psu), potential
228 !! temperature (T in deg C), and pressure in Pa. It uses the expressions
229 !! from Wright, 1997, J. Atmos. Ocean. Tech., 14, 735-740.
230 !! Coded by R. Hallberg, 1/01
231 subroutine calculate_compress_wright(T, S, pressure, rho, drho_dp, start, npts)
232  real, intent(in), dimension(:) :: T !< Potential temperature relative to the surface
233  !! in C.
234  real, intent(in), dimension(:) :: S !< Salinity in PSU.
235  real, intent(in), dimension(:) :: pressure !< Pressure in Pa.
236  real, intent(out), dimension(:) :: rho !< In situ density in kg m-3.
237  real, intent(out), dimension(:) :: drho_dp !< The partial derivative of density with pressure
238  !! (also the inverse of the square of sound speed)
239  !! in s2 m-2.
240  integer, intent(in) :: start !< The starting point in the arrays.
241  integer, intent(in) :: npts !< The number of values to calculate.
242 
243 ! * Arguments: T - potential temperature relative to the surface in C. *
244 ! * (in) S - salinity in PSU. *
245 ! * (in) pressure - pressure in Pa. *
246 ! * (out) rho - in situ density in kg m-3. *
247 ! * (out) drho_dp - the partial derivative of density with *
248 ! * pressure (also the inverse of the square of *
249 ! * sound speed) in s2 m-2. *
250 ! * (in) start - the starting point in the arrays. *
251 ! * (in) npts - the number of values to calculate. *
252 ! *====================================================================*
253 ! * This subroutine computes the in situ density of sea water (rho in *
254 ! * units of kg/m^3) and the compressibility (drho/dp = C_sound^-2) *
255 ! * (drho_dp in units of s2 m-2) from salinity (sal in psu), potential*
256 ! * temperature (T in deg C), and pressure in Pa. It uses the expres-*
257 ! * sions from Wright, 1997, J. Atmos. Ocean. Tech., 14, 735-740. *
258 ! * Coded by R. Hallberg, 1/01 *
259 ! *====================================================================*
260  real :: al0, p0, lambda, I_denom
261  integer :: j
262 
263  do j=start,start+npts-1
264  al0 = (a0 + a1*t(j)) +a2*s(j)
265  p0 = (b0 + b4*s(j)) + t(j) * (b1 + t(j)*((b2 + b3*t(j))) + b5*s(j))
266  lambda = (c0 +c4*s(j)) + t(j) * (c1 + t(j)*((c2 + c3*t(j))) + c5*s(j))
267 
268  i_denom = 1.0 / (lambda + al0*(pressure(j) + p0))
269  rho(j) = (pressure(j) + p0) * i_denom
270  drho_dp(j) = lambda * i_denom * i_denom
271  enddo
272 end subroutine calculate_compress_wright
273 
274 !> This subroutine calculates analytical and nearly-analytical integrals of
275 !! pressure anomalies across layers, which are required for calculating the
276 !! finite-volume form pressure accelerations in a Boussinesq model.
277 subroutine int_density_dz_wright(T, S, z_t, z_b, rho_ref, rho_0, G_e, HII, HIO, &
278  dpa, intz_dpa, intx_dpa, inty_dpa)
279  type(hor_index_type), intent(in) :: HII, HIO
280  real, dimension(HII%isd:HII%ied,HII%jsd:HII%jed), &
281  intent(in) :: T !< Potential temperature relative to the surface
282  !! in C.
283  real, dimension(HII%isd:HII%ied,HII%jsd:HII%jed), &
284  intent(in) :: S !< Salinity in PSU.
285  real, dimension(HII%isd:HII%ied,HII%jsd:HII%jed), &
286  intent(in) :: z_t !< Height at the top of the layer in m.
287  real, dimension(HII%isd:HII%ied,HII%jsd:HII%jed), &
288  intent(in) :: z_b !< Height at the top of the layer in m.
289  real, intent(in) :: rho_ref !< A mean density, in kg m-3, that is subtracted out
290  !! to reduce the magnitude of each of the integrals.
291  !! (The pressure is calucated as p~=-z*rho_0*G_e.)
292  real, intent(in) :: rho_0 !< Density, in kg m-3, that is used to calculate the
293  !! pressure (as p~=-z*rho_0*G_e) used in the
294  !! equation of state.
295  real, intent(in) :: G_e !< The Earth's gravitational acceleration, in m s-2.
296  real, dimension(HIO%isd:HIO%ied,HIO%jsd:HIO%jed), &
297  intent(out) :: dpa !< The change in the pressure anomaly across the
298  !! layer, in Pa.
299  real, dimension(HIO%isd:HIO%ied,HIO%jsd:HIO%jed), &
300  optional, intent(out) :: intz_dpa !< The integral through the thickness of the layer
301  !! of the pressure anomaly relative to the anomaly
302  !! at the top of the layer, in Pa m.
303  real, dimension(HIO%IsdB:HIO%IedB,HIO%jsd:HIO%jed), &
304  optional, intent(out) :: intx_dpa !< The integral in x of the difference between the
305  !! pressure anomaly at the top and bottom of the
306  !! layer divided by the x grid spacing, in Pa.
307  real, dimension(HIO%isd:HIO%ied,HIO%JsdB:HIO%JedB), &
308  optional, intent(out) :: inty_dpa !< The integral in y of the difference between the
309  !! pressure anomaly at the top and bottom of the
310  !! layer divided by the y grid spacing, in Pa.
311 
312 ! This subroutine calculates analytical and nearly-analytical integrals of
313 ! pressure anomalies across layers, which are required for calculating the
314 ! finite-volume form pressure accelerations in a Boussinesq model.
315 !
316 ! Arguments: T - potential temperature relative to the surface in C.
317 ! (in) S - salinity in PSU.
318 ! (in) z_t - height at the top of the layer in m.
319 ! (in) z_b - height at the top of the layer in m.
320 ! (in) rho_ref - A mean density, in kg m-3, that is subtracted out to reduce
321 ! the magnitude of each of the integrals.
322 ! (The pressure is calucated as p~=-z*rho_0*G_e.)
323 ! (in) rho_0 - A density, in kg m-3, that is used to calculate the pressure
324 ! (as p~=-z*rho_0*G_e) used in the equation of state.
325 ! (in) G_e - The Earth's gravitational acceleration, in m s-2.
326 ! (in) G - The ocean's grid structure.
327 ! (out) dpa - The change in the pressure anomaly across the layer,
328 ! in Pa.
329 ! (out,opt) intz_dpa - The integral through the thickness of the layer of the
330 ! pressure anomaly relative to the anomaly at the top of
331 ! the layer, in Pa m.
332 ! (out,opt) intx_dpa - The integral in x of the difference between the
333 ! pressure anomaly at the top and bottom of the layer
334 ! divided by the x grid spacing, in Pa.
335 ! (out,opt) inty_dpa - The integral in y of the difference between the
336 ! pressure anomaly at the top and bottom of the layer
337 ! divided by the y grid spacing, in Pa.
338 
339  real, dimension(HII%isd:HII%ied,HII%jsd:HII%jed) :: al0_2d, p0_2d, lambda_2d
340  real :: al0, p0, lambda
341  real :: eps, eps2, rho_anom, rem
342  real :: w_left, w_right, intz(5)
343  real, parameter :: C1_3 = 1.0/3.0, c1_7 = 1.0/7.0 ! Rational constants.
344  real, parameter :: C1_9 = 1.0/9.0, c1_90 = 1.0/90.0 ! Rational constants.
345  real :: GxRho, I_Rho
346  real :: dz, p_ave, I_al0, I_Lzz
347  integer :: is, ie, js, je, Isq, Ieq, Jsq, Jeq, i, j, ioff, joff, m
348 
349  ioff = hio%idg_offset - hii%idg_offset
350  joff = hio%jdg_offset - hii%jdg_offset
351 
352  ! These array bounds work for the indexing convention of the input arrays, but
353  ! on the computational domain defined for the output arrays.
354  isq = hio%IscB + ioff ; ieq = hio%IecB + ioff
355  jsq = hio%JscB + joff ; jeq = hio%JecB + joff
356  is = hio%isc + ioff ; ie = hio%iec + ioff
357  js = hio%jsc + joff ; je = hio%jec + joff
358 
359  gxrho = g_e * rho_0
360  i_rho = 1.0 / rho_0
361 
362  do j=jsq,jeq+1 ; do i=isq,ieq+1
363  al0_2d(i,j) = (a0 + a1*t(i,j)) + a2*s(i,j)
364  p0_2d(i,j) = (b0 + b4*s(i,j)) + t(i,j) * (b1 + t(i,j)*((b2 + b3*t(i,j))) + b5*s(i,j))
365  lambda_2d(i,j) = (c0 +c4*s(i,j)) + t(i,j) * (c1 + t(i,j)*((c2 + c3*t(i,j))) + c5*s(i,j))
366 
367  al0 = al0_2d(i,j) ; p0 = p0_2d(i,j) ; lambda = lambda_2d(i,j)
368 
369  dz = z_t(i,j) - z_b(i,j)
370  p_ave = -0.5*gxrho*(z_t(i,j)+z_b(i,j))
371 
372  i_al0 = 1.0 / al0
373  i_lzz = 1.0 / (p0 + (lambda * i_al0) + p_ave)
374  eps = 0.5*gxrho*dz*i_lzz ; eps2 = eps*eps
375 
376 ! rho(j) = (pressure(j) + p0) / (lambda + al0*(pressure(j) + p0))
377 
378  rho_anom = (p0 + p_ave)*(i_lzz*i_al0) - rho_ref
379  rem = i_rho * (lambda * i_al0**2) * eps2 * &
380  (c1_3 + eps2*(0.2 + eps2*(c1_7 + c1_9*eps2)))
381  dpa(i-ioff,j-joff) = g_e*rho_anom*dz - 2.0*eps*rem
382  if (present(intz_dpa)) &
383  intz_dpa(i-ioff,j-joff) = 0.5*g_e*rho_anom*dz**2 - dz*(1.0+eps)*rem
384  enddo ; enddo
385 
386  if (present(intx_dpa)) then ; do j=js,je ; do i=isq,ieq
387  intz(1) = dpa(i-ioff,j-joff) ; intz(5) = dpa(i+1-ioff,j-joff)
388  do m=2,4
389  w_left = 0.25*real(m-1) ; w_right = 1.0-w_left
390  al0 = w_left*al0_2d(i,j) + w_right*al0_2d(i+1,j)
391  p0 = w_left*p0_2d(i,j) + w_right*p0_2d(i+1,j)
392  lambda = w_left*lambda_2d(i,j) + w_right*lambda_2d(i+1,j)
393 
394  dz = w_left*(z_t(i,j) - z_b(i,j)) + w_right*(z_t(i+1,j) - z_b(i+1,j))
395  p_ave = -0.5*gxrho*(w_left*(z_t(i,j)+z_b(i,j)) + &
396  w_right*(z_t(i+1,j)+z_b(i+1,j)))
397 
398  i_al0 = 1.0 / al0
399  i_lzz = 1.0 / (p0 + (lambda * i_al0) + p_ave)
400  eps = 0.5*gxrho*dz*i_lzz ; eps2 = eps*eps
401 
402  intz(m) = g_e*dz*((p0 + p_ave)*(i_lzz*i_al0) - rho_ref) - 2.0*eps * &
403  i_rho * (lambda * i_al0**2) * eps2 * &
404  (c1_3 + eps2*(0.2 + eps2*(c1_7 + c1_9*eps2)))
405  enddo
406  ! Use Bode's rule to integrate the values.
407  intx_dpa(i-ioff,j-joff) = c1_90*(7.0*(intz(1)+intz(5)) + 32.0*(intz(2)+intz(4)) + &
408  12.0*intz(3))
409  enddo ; enddo ; endif
410 
411  if (present(inty_dpa)) then ; do j=jsq,jeq ; do i=is,ie
412  intz(1) = dpa(i-ioff,j-joff) ; intz(5) = dpa(i-ioff,j+1-joff)
413  do m=2,4
414  w_left = 0.25*real(m-1) ; w_right = 1.0-w_left
415  al0 = w_left*al0_2d(i,j) + w_right*al0_2d(i,j+1)
416  p0 = w_left*p0_2d(i,j) + w_right*p0_2d(i,j+1)
417  lambda = w_left*lambda_2d(i,j) + w_right*lambda_2d(i,j+1)
418 
419  dz = w_left*(z_t(i,j) - z_b(i,j)) + w_right*(z_t(i,j+1) - z_b(i,j+1))
420  p_ave = -0.5*gxrho*(w_left*(z_t(i,j)+z_b(i,j)) + &
421  w_right*(z_t(i,j+1)+z_b(i,j+1)))
422 
423  i_al0 = 1.0 / al0
424  i_lzz = 1.0 / (p0 + (lambda * i_al0) + p_ave)
425  eps = 0.5*gxrho*dz*i_lzz ; eps2 = eps*eps
426 
427  intz(m) = g_e*dz*((p0 + p_ave)*(i_lzz*i_al0) - rho_ref) - 2.0*eps * &
428  i_rho * (lambda * i_al0**2) * eps2 * &
429  (c1_3 + eps2*(0.2 + eps2*(c1_7 + c1_9*eps2)))
430  enddo
431  ! Use Bode's rule to integrate the values.
432  inty_dpa(i-ioff,j-joff) = c1_90*(7.0*(intz(1)+intz(5)) + 32.0*(intz(2)+intz(4)) + &
433  12.0*intz(3))
434  enddo ; enddo ; endif
435 end subroutine int_density_dz_wright
436 
437 !> This subroutine calculates analytical and nearly-analytical integrals in
438 !! pressure across layers of geopotential anomalies, which are required for
439 !! calculating the finite-volume form pressure accelerations in a non-Boussinesq
440 !! model. There are essentially no free assumptions, apart from the use of
441 !! Bode's rule to do the horizontal integrals, and from a truncation in the
442 !! series for log(1-eps/1+eps) that assumes that |eps| < 0.34.
443 subroutine int_spec_vol_dp_wright(T, S, p_t, p_b, alpha_ref, HI, dza, &
444  intp_dza, intx_dza, inty_dza, halo_size)
445  type(hor_index_type), intent(in) :: HI
446  real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), &
447  intent(in) :: T !< Potential temperature relative to the surface
448  !! in C.
449  real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), &
450  intent(in) :: S !< Salinity in PSU.
451  real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), &
452  intent(in) :: p_t !< Pressure at the top of the layer in Pa.
453  real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), &
454  intent(in) :: p_b !< Pressure at the top of the layer in Pa.
455  real, intent(in) :: alpha_ref !< A mean specific volume that is subtracted out
456  !! to reduce the magnitude of each of the integrals, m3 kg-1.The calculation is
457  !! mathematically identical with different values of alpha_ref, but this reduces the
458  !! effects of roundoff.
459  real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), &
460  intent(out) :: dza !< The change in the geopotential anomaly across
461  !! the layer, in m2 s-2.
462  real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), &
463  optional, intent(out) :: intp_dza !< The integral in pressure through the layer of
464  !! the geopotential anomaly relative to the anomaly
465  !! at the bottom of the layer, in Pa m2 s-2.
466  real, dimension(HI%IsdB:HI%IedB,HI%jsd:HI%jed), &
467  optional, intent(out) :: intx_dza !< The integral in x of the difference between the
468  !! geopotential anomaly at the top and bottom of
469  !! the layer divided by the x grid spacing,
470  !! in m2 s-2.
471  real, dimension(HI%isd:HI%ied,HI%JsdB:HI%JedB), &
472  optional, intent(out) :: inty_dza !< The integral in y of the difference between the
473  !! geopotential anomaly at the top and bottom of
474  !! the layer divided by the y grid spacing,
475  !! in m2 s-2.
476  integer, optional, intent(in) :: halo_size !< The width of halo points on which to calculate
477  !! dza.
478 
479 ! This subroutine calculates analytical and nearly-analytical integrals in
480 ! pressure across layers of geopotential anomalies, which are required for
481 ! calculating the finite-volume form pressure accelerations in a non-Boussinesq
482 ! model. There are essentially no free assumptions, apart from the use of
483 ! Bode's rule to do the horizontal integrals, and from a truncation in the
484 ! series for log(1-eps/1+eps) that assumes that |eps| < 0.34.
485 !
486 ! Arguments: T - potential temperature relative to the surface in C.
487 ! (in) S - salinity in PSU.
488 ! (in) p_t - pressure at the top of the layer in Pa.
489 ! (in) p_b - pressure at the top of the layer in Pa.
490 ! (in) alpha_ref - A mean specific volume that is subtracted out to reduce
491 ! the magnitude of each of the integrals, m3 kg-1.
492 ! The calculation is mathematically identical with
493 ! different values of alpha_ref, but this reduces the
494 ! effects of roundoff.
495 ! (in) HI - The ocean's horizontal index structure.
496 ! (out) dza - The change in the geopotential anomaly across the layer,
497 ! in m2 s-2.
498 ! (out,opt) intp_dza - The integral in pressure through the layer of the
499 ! geopotential anomaly relative to the anomaly at the
500 ! bottom of the layer, in Pa m2 s-2.
501 ! (out,opt) intx_dza - The integral in x of the difference between the
502 ! geopotential anomaly at the top and bottom of the layer
503 ! divided by the x grid spacing, in m2 s-2.
504 ! (out,opt) inty_dza - The integral in y of the difference between the
505 ! geopotential anomaly at the top and bottom of the layer
506 ! divided by the y grid spacing, in m2 s-2.
507 ! (in,opt) halo_size - The width of halo points on which to calculate dza.
508 
509  real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed) :: al0_2d, p0_2d, lambda_2d
510  real :: al0, p0, lambda
511  real :: alpha_anom, dp, p_ave
512  real :: rem, eps, eps2
513  real :: w_left, w_right, intp(5)
514  real, parameter :: C1_3 = 1.0/3.0, c1_7 = 1.0/7.0 ! Rational constants.
515  real, parameter :: C1_9 = 1.0/9.0, c1_90 = 1.0/90.0 ! Rational constants.
516  integer :: Isq, Ieq, Jsq, Jeq, ish, ieh, jsh, jeh, i, j, m, halo
517 
518  isq = hi%IscB ; ieq = hi%IecB ; jsq = hi%JscB ; jeq = hi%JecB
519  halo = 0 ; if (present(halo_size)) halo = max(halo_size,0)
520  ish = hi%isc-halo ; ieh = hi%iec+halo ; jsh = hi%jsc-halo ; jeh = hi%jec+halo
521  if (present(intx_dza)) then ; ish = min(isq,ish) ; ieh = max(ieq+1,ieh); endif
522  if (present(inty_dza)) then ; jsh = min(jsq,jsh) ; jeh = max(jeq+1,jeh); endif
523 
524  if (present(intp_dza)) then
525  do j=jsh,jeh ; do i=ish,ieh
526  al0_2d(i,j) = (a0 + a1*t(i,j)) + a2*s(i,j)
527  p0_2d(i,j) = (b0 + b4*s(i,j)) + t(i,j) * (b1 + t(i,j)*((b2 + b3*t(i,j))) + b5*s(i,j))
528  lambda_2d(i,j) = (c0 +c4*s(i,j)) + t(i,j) * (c1 + t(i,j)*((c2 + c3*t(i,j))) + c5*s(i,j))
529 
530  al0 = al0_2d(i,j) ; p0 = p0_2d(i,j) ; lambda = lambda_2d(i,j)
531  dp = p_b(i,j) - p_t(i,j)
532  p_ave = 0.5*(p_t(i,j)+p_b(i,j))
533 
534  eps = 0.5 * dp / (p0 + p_ave) ; eps2 = eps*eps
535  alpha_anom = al0 + lambda / (p0 + p_ave) - alpha_ref
536  rem = lambda * eps2 * (c1_3 + eps2*(0.2 + eps2*(c1_7 + c1_9*eps2)))
537  dza(i,j) = alpha_anom*dp + 2.0*eps*rem
538  intp_dza(i,j) = 0.5*alpha_anom*dp**2 - dp*(1.0-eps)*rem
539  enddo ; enddo
540  else
541  do j=jsh,jeh ; do i=ish,ieh
542  al0_2d(i,j) = (a0 + a1*t(i,j)) + a2*s(i,j)
543  p0_2d(i,j) = (b0 + b4*s(i,j)) + t(i,j) * (b1 + t(i,j)*((b2 + b3*t(i,j))) + b5*s(i,j))
544  lambda_2d(i,j) = (c0 +c4*s(i,j)) + t(i,j) * (c1 + t(i,j)*((c2 + c3*t(i,j))) + c5*s(i,j))
545 
546  al0 = al0_2d(i,j) ; p0 = p0_2d(i,j) ; lambda = lambda_2d(i,j)
547  dp = p_b(i,j) - p_t(i,j)
548  p_ave = 0.5*(p_t(i,j)+p_b(i,j))
549 
550  eps = 0.5 * dp / (p0 + p_ave) ; eps2 = eps*eps
551  alpha_anom = al0 + lambda / (p0 + p_ave) - alpha_ref
552  rem = lambda * eps2 * (c1_3 + eps2*(0.2 + eps2*(c1_7 + c1_9*eps2)))
553  dza(i,j) = alpha_anom*dp + 2.0*eps*rem
554  enddo ; enddo
555  endif
556 
557  if (present(intx_dza)) then ; do j=hi%jsc,hi%jec ; do i=isq,ieq
558  intp(1) = dza(i,j) ; intp(5) = dza(i+1,j)
559  do m=2,4
560  w_left = 0.25*real(5-m) ; w_right = 1.0-w_left
561  al0 = w_left*al0_2d(i,j) + w_right*al0_2d(i+1,j)
562  p0 = w_left*p0_2d(i,j) + w_right*p0_2d(i+1,j)
563  lambda = w_left*lambda_2d(i,j) + w_right*lambda_2d(i+1,j)
564 
565  dp = w_left*(p_b(i,j) - p_t(i,j)) + w_right*(p_b(i+1,j) - p_t(i+1,j))
566  p_ave = 0.5*(w_left*(p_t(i,j)+p_b(i,j)) + w_right*(p_t(i+1,j)+p_b(i+1,j)))
567 
568  eps = 0.5 * dp / (p0 + p_ave) ; eps2 = eps*eps
569  intp(m) = (al0 + lambda / (p0 + p_ave) - alpha_ref)*dp + 2.0*eps* &
570  lambda * eps2 * (c1_3 + eps2*(0.2 + eps2*(c1_7 + c1_9*eps2)))
571  enddo
572  ! Use Bode's rule to integrate the values.
573  intx_dza(i,j) = c1_90*(7.0*(intp(1)+intp(5)) + 32.0*(intp(2)+intp(4)) + &
574  12.0*intp(3))
575  enddo ; enddo ; endif
576 
577  if (present(inty_dza)) then ; do j=jsq,jeq ; do i=hi%isc,hi%iec
578  intp(1) = dza(i,j) ; intp(5) = dza(i,j+1)
579  do m=2,4
580  w_left = 0.25*real(5-m) ; w_right = 1.0-w_left
581  al0 = w_left*al0_2d(i,j) + w_right*al0_2d(i,j+1)
582  p0 = w_left*p0_2d(i,j) + w_right*p0_2d(i,j+1)
583  lambda = w_left*lambda_2d(i,j) + w_right*lambda_2d(i,j+1)
584 
585  dp = w_left*(p_b(i,j) - p_t(i,j)) + w_right*(p_b(i,j+1) - p_t(i,j+1))
586  p_ave = 0.5*(w_left*(p_t(i,j)+p_b(i,j)) + w_right*(p_t(i,j+1)+p_b(i,j+1)))
587 
588  eps = 0.5 * dp / (p0 + p_ave) ; eps2 = eps*eps
589  intp(m) = (al0 + lambda / (p0 + p_ave) - alpha_ref)*dp + 2.0*eps* &
590  lambda * eps2 * (c1_3 + eps2*(0.2 + eps2*(c1_7 + c1_9*eps2)))
591  enddo
592  ! Use Bode's rule to integrate the values.
593  inty_dza(i,j) = c1_90*(7.0*(intp(1)+intp(5)) + 32.0*(intp(2)+intp(4)) + &
594  12.0*intp(3))
595  enddo ; enddo ; endif
596 end subroutine int_spec_vol_dp_wright
597 
598 end module mom_eos_wright
real, parameter a2
real, parameter b4
real, parameter c4
subroutine, public calculate_density_derivs_wright(T, S, pressure, drho_dT, drho_dS, start, npts)
real, parameter b1
real, parameter a0
subroutine, public calculate_density_scalar_wright(T, S, pressure, rho)
This subroutine computes the in situ density of sea water (rho in units of kg/m^3) from salinity (S i...
real, parameter c5
Defines the horizontal index type (hor_index_type) used for providing index ranges.
real, parameter b3
Container for horizontal index ranges for data, computational and global domains. ...
real, parameter c2
real, parameter c0
real, parameter b2
subroutine, public calculate_specvol_derivs_wright(T, S, pressure, dSV_dT, dSV_dS, start, npts)
real, parameter c3
subroutine, public calculate_compress_wright(T, S, pressure, rho, drho_dp, start, npts)
This subroutine computes the in situ density of sea water (rho in units of kg/m^3) and the compressib...
subroutine, public int_spec_vol_dp_wright(T, S, p_t, p_b, alpha_ref, HI, dza, intp_dza, intx_dza, inty_dza, halo_size)
This subroutine calculates analytical and nearly-analytical integrals in pressure across layers of ge...
real, parameter b5
real, parameter c1
subroutine, public calculate_density_array_wright(T, S, pressure, rho, start, npts)
This subroutine computes the in situ density of sea water (rho in units of kg/m^3) from salinity (S i...
real, parameter a1
real, parameter b0
subroutine, public int_density_dz_wright(T, S, z_t, z_b, rho_ref, rho_0, G_e, HII, HIO, dpa, intz_dpa, intx_dpa, inty_dpa)
This subroutine calculates analytical and nearly-analytical integrals of pressure anomalies across la...