MOM6
MOM_EOS_UNESCO.F90
1 !> The equation of state using the Jackett and McDougall fits to the UNESCO EOS
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 !***********************************************************************
7 !* The subroutines in this file implement the equation of state for *
8 !* sea water using the fit to the UNESCO equation of state given by *
9 !* the expressions from Jackett and McDougall, 1995, J. Atmos. *
10 !* Ocean. Tech., 12, 381-389. Coded by J. Stephens, 9/99. *
11 !***********************************************************************
12 
13 implicit none ; private
14 
15 public calculate_compress_unesco, calculate_density_unesco, calculate_spec_vol_unesco
16 public calculate_density_derivs_unesco
17 public calculate_density_scalar_unesco, calculate_density_array_unesco
18 
19 !> Compute the in situ density of sea water (in [kg m-3]), or its anomaly with respect to
20 !! a reference density, from salinity [PSU], potential temperature [degC], and pressure [Pa],
21 !! using the UNESCO (1981) equation of state.
23  module procedure calculate_density_scalar_unesco, calculate_density_array_unesco
24 end interface calculate_density_unesco
25 
26 !> Compute the in situ specific volume of sea water (in [m3 kg-1]), or an anomaly with respect
27 !! to a reference specific volume, from salinity [PSU], potential temperature [degC], and
28 !! pressure [Pa], using the UNESCO (1981) equation of state.
30  module procedure calculate_spec_vol_scalar_unesco, calculate_spec_vol_array_unesco
31 end interface calculate_spec_vol_unesco
32 
33 !>@{ Parameters in the UNESCO equation of state
34 ! The following constants are used to calculate rho0. The notation
35 ! is Rab for the contribution to rho0 from T^aS^b.
36 real, parameter :: r00 = 999.842594, r10 = 6.793952e-2, r20 = -9.095290e-3, &
37  r30 = 1.001685e-4, r40 = -1.120083e-6, r50 = 6.536332e-9, r01 = 0.824493, &
38  r11 = -4.0899e-3, r21 = 7.6438e-5, r31 = -8.2467e-7, r41 = 5.3875e-9, &
39  r032 = -5.72466e-3, r132 = 1.0227e-4, r232 = -1.6546e-6, r02 = 4.8314e-4
40 
41 ! The following constants are used to calculate the secant bulk mod-
42 ! ulus. The notation here is Sab for terms proportional to T^a*S^b,
43 ! Spab for terms proportional to p*T^a*S^b, and SPab for terms
44 ! proportional to p^2*T^a*S^b.
45 real, parameter :: s00 = 1.965933e4, s10 = 1.444304e2, s20 = -1.706103, &
46  s30 = 9.648704e-3, s40 = -4.190253e-5, s01 = 52.84855, s11 = -3.101089e-1, &
47  s21 = 6.283263e-3, s31 = -5.084188e-5, s032 = 3.886640e-1, s132 = 9.085835e-3, &
48  s232 = -4.619924e-4, sp00 = 3.186519, sp10 = 2.212276e-2, sp20 = -2.984642e-4, &
49  sp30 = 1.956415e-6, sp01 = 6.704388e-3, sp11 = -1.847318e-4, sp21 = 2.059331e-7, &
50  sp032 = 1.480266e-4, sp000 = 2.102898e-4, sp010 = -1.202016e-5, sp020 = 1.394680e-7, &
51  sp001 = -2.040237e-6, sp011 = 6.128773e-8, sp021 = 6.207323e-10
52 !!@}
53 
54 contains
55 
56 !> This subroutine computes the in situ density of sea water (rho in
57 !! [kg m-3]) from salinity (S [PSU]), potential temperature
58 !! (T [degC]), and pressure [Pa], using the UNESCO (1981) equation of state.
59 subroutine calculate_density_scalar_unesco(T, S, pressure, rho, rho_ref)
60  real, intent(in) :: t !< Potential temperature relative to the surface [degC].
61  real, intent(in) :: s !< Salinity [PSU].
62  real, intent(in) :: pressure !< pressure [Pa].
63  real, intent(out) :: rho !< In situ density [kg m-3].
64  real, optional, intent(in) :: rho_ref !< A reference density [kg m-3].
65 
66  ! Local variables
67  real, dimension(1) :: t0, s0, pressure0
68  real, dimension(1) :: rho0
69 
70  t0(1) = t
71  s0(1) = s
72  pressure0(1) = pressure
73 
74  call calculate_density_array_unesco(t0, s0, pressure0, rho0, 1, 1, rho_ref)
75  rho = rho0(1)
76 
77 end subroutine calculate_density_scalar_unesco
78 
79 !> This subroutine computes the in situ density of sea water (rho in
80 !! [kg m-3]) from salinity (S [PSU]), potential temperature
81 !! (T [degC]), and pressure [Pa], using the UNESCO (1981) equation of state.
82 subroutine calculate_density_array_unesco(T, S, pressure, rho, start, npts, rho_ref)
83  real, dimension(:), intent(in) :: t !< potential temperature relative to the surface [degC].
84  real, dimension(:), intent(in) :: s !< salinity [PSU].
85  real, dimension(:), intent(in) :: pressure !< pressure [Pa].
86  real, dimension(:), intent(out) :: rho !< in situ density [kg m-3].
87  integer, intent(in) :: start !< the starting point in the arrays.
88  integer, intent(in) :: npts !< the number of values to calculate.
89  real, optional, intent(in) :: rho_ref !< A reference density [kg m-3].
90 
91  ! Local variables
92  real :: t_local, t2, t3, t4, t5 ! Temperature to the 1st - 5th power [degC^n].
93  real :: s_local, s32, s2 ! Salinity to the 1st, 3/2, & 2nd power [PSU^n].
94  real :: p1, p2 ! Pressure (in bars) to the 1st and 2nd power [bar] and [bar2].
95  real :: rho0 ! Density at 1 bar pressure [kg m-3].
96  real :: sig0 ! The anomaly of rho0 from R00 [kg m-3].
97  real :: ks ! The secant bulk modulus [bar].
98  integer :: j
99 
100  do j=start,start+npts-1
101  if (s(j) < -1.0e-10) then !Can we assume safely that this is a missing value?
102  rho(j) = 1000.0
103  cycle
104  endif
105 
106  p1 = pressure(j)*1.0e-5; p2 = p1*p1
107  t_local = t(j); t2 = t_local*t_local; t3 = t_local*t2; t4 = t2*t2; t5 = t3*t2
108  s_local = s(j); s2 = s_local*s_local; s32 = s_local*sqrt(s_local)
109 
110 ! Compute rho(s,theta,p=0) - (same as rho(s,t_insitu,p=0) ).
111 
112  sig0 = r10*t_local + r20*t2 + r30*t3 + r40*t4 + r50*t5 + &
113  s_local*(r01 + r11*t_local + r21*t2 + r31*t3 + r41*t4) + &
114  s32*(r032 + r132*t_local + r232*t2) + r02*s2
115  rho0 = r00 + sig0
116 
117 ! Compute rho(s,theta,p), first calculating the secant bulk modulus.
118 
119  ks = s00 + s10*t_local + s20*t2 + s30*t3 + s40*t4 + s_local*(s01 + s11*t_local + s21*t2 + s31*t3) + &
120  s32*(s032 + s132*t_local + s232*t2) + &
121  p1*(sp00 + sp10*t_local + sp20*t2 + sp30*t3 + &
122  s_local*(sp01 + sp11*t_local + sp21*t2) + sp032*s32) + &
123  p2*(sp000 + sp010*t_local + sp020*t2 + s_local*(sp001 + sp011*t_local + sp021*t2))
124 
125  if (present(rho_ref)) then
126  rho(j) = ((r00 - rho_ref)*ks + (sig0*ks + p1*rho_ref)) / (ks - p1)
127  else
128  rho(j) = rho0*ks / (ks - p1)
129  endif
130  enddo
131 end subroutine calculate_density_array_unesco
132 
133 !> This subroutine computes the in situ specific volume of sea water (specvol in
134 !! [m3 kg-1]) from salinity (S [PSU]), potential temperature (T [degC])
135 !! and pressure [Pa], using the UNESCO (1981) equation of state.
136 !! If spv_ref is present, specvol is an anomaly from spv_ref.
137 subroutine calculate_spec_vol_scalar_unesco(T, S, pressure, specvol, spv_ref)
138  real, intent(in) :: T !< potential temperature relative to the surface
139  !! [degC].
140  real, intent(in) :: S !< salinity [PSU].
141  real, intent(in) :: pressure !< pressure [Pa].
142  real, intent(out) :: specvol !< in situ specific volume [m3 kg-1].
143  real, optional, intent(in) :: spv_ref !< A reference specific volume [m3 kg-1].
144 
145  ! Local variables
146  real, dimension(1) :: T0, S0, pressure0, spv0
147 
148  t0(1) = t ; s0(1) = s ; pressure0(1) = pressure
149 
150  call calculate_spec_vol_array_unesco(t0, s0, pressure0, spv0, 1, 1, spv_ref)
151  specvol = spv0(1)
152 end subroutine calculate_spec_vol_scalar_unesco
153 
154 !> This subroutine computes the in situ specific volume of sea water (specvol in
155 !! [m3 kg-1]) from salinity (S [PSU]), potential temperature (T [degC])
156 !! and pressure [Pa], using the UNESCO (1981) equation of state.
157 !! If spv_ref is present, specvol is an anomaly from spv_ref.
158 subroutine calculate_spec_vol_array_unesco(T, S, pressure, specvol, start, npts, spv_ref)
159  real, dimension(:), intent(in) :: T !< potential temperature relative to the surface
160  !! [degC].
161  real, dimension(:), intent(in) :: S !< salinity [PSU].
162  real, dimension(:), intent(in) :: pressure !< pressure [Pa].
163  real, dimension(:), intent(out) :: specvol !< in situ specific volume [m3 kg-1].
164  integer, intent(in) :: start !< the starting point in the arrays.
165  integer, intent(in) :: npts !< the number of values to calculate.
166  real, optional, intent(in) :: spv_ref !< A reference specific volume [m3 kg-1].
167 
168  ! Local variables
169  real :: t_local, t2, t3, t4, t5 ! Temperature to the 1st - 5th power [degC^n].
170  real :: s_local, s32, s2 ! Salinity to the 1st, 3/2, & 2nd power [PSU^n].
171  real :: p1, p2 ! Pressure (in bars) to the 1st and 2nd power [bar] and [bar2].
172  real :: rho0 ! Density at 1 bar pressure [kg m-3].
173  real :: ks ! The secant bulk modulus [bar].
174  integer :: j
175 
176  do j=start,start+npts-1
177  if (s(j) < -1.0e-10) then !Can we assume safely that this is a missing value?
178  specvol(j) = 0.001
179  if (present(spv_ref)) specvol(j) = 0.001 - spv_ref
180  cycle
181  endif
182 
183  p1 = pressure(j)*1.0e-5; p2 = p1*p1
184  t_local = t(j); t2 = t_local*t_local; t3 = t_local*t2; t4 = t2*t2; t5 = t3*t2
185  s_local = s(j); s2 = s_local*s_local; s32 = s_local*sqrt(s_local)
186 
187 ! Compute rho(s,theta,p=0) - (same as rho(s,t_insitu,p=0) ).
188 
189  rho0 = r00 + r10*t_local + r20*t2 + r30*t3 + r40*t4 + r50*t5 + &
190  s_local*(r01 + r11*t_local + r21*t2 + r31*t3 + r41*t4) + &
191  s32*(r032 + r132*t_local + r232*t2) + r02*s2
192 
193 ! Compute rho(s,theta,p), first calculating the secant bulk modulus.
194 
195  ks = s00 + s10*t_local + s20*t2 + s30*t3 + s40*t4 + s_local*(s01 + s11*t_local + s21*t2 + s31*t3) + &
196  s32*(s032 + s132*t_local + s232*t2) + &
197  p1*(sp00 + sp10*t_local + sp20*t2 + sp30*t3 + &
198  s_local*(sp01 + sp11*t_local + sp21*t2) + sp032*s32) + &
199  p2*(sp000 + sp010*t_local + sp020*t2 + s_local*(sp001 + sp011*t_local + sp021*t2))
200 
201  if (present(spv_ref)) then
202  specvol(j) = (ks*(1.0 - (rho0*spv_ref)) - p1) / (rho0*ks)
203  else
204  specvol(j) = (ks - p1) / (rho0*ks)
205  endif
206  enddo
207 end subroutine calculate_spec_vol_array_unesco
208 
209 
210 !> This subroutine calculates the partial derivatives of density
211 !! with potential temperature and salinity.
212 subroutine calculate_density_derivs_unesco(T, S, pressure, drho_dT, drho_dS, start, npts)
213  real, intent(in), dimension(:) :: t !< Potential temperature relative to the surface
214  !! [degC].
215  real, intent(in), dimension(:) :: s !< Salinity [PSU].
216  real, intent(in), dimension(:) :: pressure !< Pressure [Pa].
217  real, intent(out), dimension(:) :: drho_dt !< The partial derivative of density with potential
218  !! temperature [kg m-3 degC-1].
219  real, intent(out), dimension(:) :: drho_ds !< The partial derivative of density with salinity,
220  !! in [kg m-3 PSU-1].
221  integer, intent(in) :: start !< The starting point in the arrays.
222  integer, intent(in) :: npts !< The number of values to calculate.
223 
224  ! Local variables
225  real :: t_local, t2, t3, t4, t5 ! Temperature to the 1st - 5th power [degC^n].
226  real :: s12, s_local, s32, s2 ! Salinity to the 1/2 - 2nd powers [PSU^n].
227  real :: p1, p2 ! Pressure to the 1st & 2nd power [bar] and [bar2].
228  real :: rho0 ! Density at 1 bar pressure [kg m-3].
229  real :: ks ! The secant bulk modulus [bar].
230  real :: drho0_dt ! Derivative of rho0 with T [kg m-3 degC-1].
231  real :: drho0_ds ! Derivative of rho0 with S [kg m-3 PSU-1].
232  real :: dks_dt ! Derivative of ks with T [bar degC-1].
233  real :: dks_ds ! Derivative of ks with S [bar psu-1].
234  real :: denom ! 1.0 / (ks - p1) [bar-1].
235  integer :: j
236 
237  do j=start,start+npts-1
238  if (s(j) < -1.0e-10) then !Can we assume safely that this is a missing value?
239  drho_dt(j) = 0.0 ; drho_ds(j) = 0.0
240  cycle
241  endif
242 
243  p1 = pressure(j)*1.0e-5; p2 = p1*p1
244  t_local = t(j); t2 = t_local*t_local; t3 = t_local*t2; t4 = t2*t2; t5 = t3*t2
245  s_local = s(j); s2 = s_local*s_local; s12 = sqrt(s_local); s32 = s_local*s12
246 
247 ! compute rho(s,theta,p=0) - (same as rho(s,t_insitu,p=0) )
248 
249  rho0 = r00 + r10*t_local + r20*t2 + r30*t3 + r40*t4 + r50*t5 + &
250  s_local*(r01 + r11*t_local + r21*t2 + r31*t3 + r41*t4) + &
251  s32*(r032 + r132*t_local + r232*t2) + r02*s2
252  drho0_dt = r10 + 2.0*r20*t_local + 3.0*r30*t2 + 4.0*r40*t3 + 5.0*r50*t4 + &
253  s_local*(r11 + 2.0*r21*t_local + 3.0*r31*t2 + 4.0*r41*t3) + &
254  s32*(r132 + 2.0*r232*t_local)
255  drho0_ds = (r01 + r11*t_local + r21*t2 + r31*t3 + r41*t4) + &
256  1.5*s12*(r032 + r132*t_local + r232*t2) + 2.0*r02*s_local
257 
258 ! compute rho(s,theta,p)
259 
260  ks = s00 + s10*t_local + s20*t2 + s30*t3 + s40*t4 + s_local*(s01 + s11*t_local + s21*t2 + s31*t3) + &
261  s32*(s032 + s132*t_local + s232*t2) + &
262  p1*(sp00 + sp10*t_local + sp20*t2 + sp30*t3 + &
263  s_local*(sp01 + sp11*t_local + sp21*t2) + sp032*s32) + &
264  p2*(sp000 + sp010*t_local + sp020*t2 + s_local*(sp001 + sp011*t_local + sp021*t2))
265  dks_dt = s10 + 2.0*s20*t_local + 3.0*s30*t2 + 4.0*s40*t3 + &
266  s_local*(s11 + 2.0*s21*t_local + 3.0*s31*t2) + s32*(s132 + 2.0*s232*t_local) + &
267  p1*(sp10 + 2.0*sp20*t_local + 3.0*sp30*t2 + s_local*(sp11 + 2.0*sp21*t_local)) + &
268  p2*(sp010 + 2.0*sp020*t_local + s_local*(sp011 + 2.0*sp021*t_local))
269  dks_ds = (s01 + s11*t_local + s21*t2 + s31*t3) + 1.5*s12*(s032 + s132*t_local + s232*t2) + &
270  p1*(sp01 + sp11*t_local + sp21*t2 + 1.5*sp032*s12) + &
271  p2*(sp001 + sp011*t_local + sp021*t2)
272 
273  denom = 1.0 / (ks - p1)
274  drho_dt(j) = denom*(ks*drho0_dt - rho0*p1*denom*dks_dt)
275  drho_ds(j) = denom*(ks*drho0_ds - rho0*p1*denom*dks_ds)
276  enddo
277 
278 end subroutine calculate_density_derivs_unesco
279 
280 !> This subroutine computes the in situ density of sea water (rho)
281 !! and the compressibility (drho/dp == C_sound^-2) at the given
282 !! salinity, potential temperature, and pressure.
283 subroutine calculate_compress_unesco(T, S, pressure, rho, drho_dp, start, npts)
284  real, intent(in), dimension(:) :: t !< Potential temperature relative to the surface
285  !! [degC].
286  real, intent(in), dimension(:) :: s !< Salinity [PSU].
287  real, intent(in), dimension(:) :: pressure !< Pressure [Pa].
288  real, intent(out), dimension(:) :: rho !< In situ density [kg m-3].
289  real, intent(out), dimension(:) :: drho_dp !< The partial derivative of density with pressure
290  !! (also the inverse of the square of sound speed)
291  !! [s2 m-2].
292  integer, intent(in) :: start !< The starting point in the arrays.
293  integer, intent(in) :: npts !< The number of values to calculate.
294 
295  ! Local variables
296  real :: t_local, t2, t3, t4, t5 ! Temperature to the 1st - 5th power [degC^n].
297  real :: s_local, s32, s2 ! Salinity to the 1st, 3/2, & 2nd power [PSU^n].
298  real :: p1, p2 ! Pressure to the 1st & 2nd power [bar] and [bar2].
299  real :: rho0 ! Density at 1 bar pressure [kg m-3].
300  real :: ks ! The secant bulk modulus [bar].
301  real :: ks_0, ks_1, ks_2
302  real :: dks_dp ! The derivative of the secant bulk modulus
303  ! with pressure, nondimensional.
304  integer :: j
305 
306  do j=start,start+npts-1
307  if (s(j) < -1.0e-10) then !Can we assume safely that this is a missing value?
308  rho(j) = 1000.0 ; drho_dp(j) = 0.0
309  cycle
310  endif
311 
312  p1 = pressure(j)*1.0e-5; p2 = p1*p1
313  t_local = t(j); t2 = t_local*t_local; t3 = t_local*t2; t4 = t2*t2; t5 = t3*t2
314  s_local = s(j); s2 = s_local*s_local; s32 = s_local*sqrt(s_local)
315 
316 ! Compute rho(s,theta,p=0) - (same as rho(s,t_insitu,p=0) ).
317 
318  rho0 = r00 + r10*t_local + r20*t2 + r30*t3 + r40*t4 + r50*t5 + &
319  s_local*(r01 + r11*t_local + r21*t2 + r31*t3 + r41*t4) + &
320  s32*(r032 + r132*t_local + r232*t2) + r02*s2
321 
322 ! Compute rho(s,theta,p), first calculating the secant bulk modulus.
323  ks_0 = s00 + s10*t_local + s20*t2 + s30*t3 + s40*t4 + &
324  s_local*(s01 + s11*t_local + s21*t2 + s31*t3) + s32*(s032 + s132*t_local + s232*t2)
325  ks_1 = sp00 + sp10*t_local + sp20*t2 + sp30*t3 + &
326  s_local*(sp01 + sp11*t_local + sp21*t2) + sp032*s32
327  ks_2 = sp000 + sp010*t_local + sp020*t2 + s_local*(sp001 + sp011*t_local + sp021*t2)
328 
329  ks = ks_0 + p1*ks_1 + p2*ks_2
330  dks_dp = ks_1 + 2.0*p1*ks_2
331 
332  rho(j) = rho0*ks / (ks - p1)
333 ! The factor of 1.0e-5 is because pressure here is in bars, not Pa.
334  drho_dp(j) = 1.0e-5 * (rho(j) / (ks - p1)) * (1.0 - dks_dp*p1/ks)
335  enddo
336 end subroutine calculate_compress_unesco
337 
338 
339 end module mom_eos_unesco
mom_eos_unesco::calculate_spec_vol_unesco
Compute the in situ specific volume of sea water (in [m3 kg-1]), or an anomaly with respect to a refe...
Definition: MOM_EOS_UNESCO.F90:29
mom_eos_unesco
The equation of state using the Jackett and McDougall fits to the UNESCO EOS.
Definition: MOM_EOS_UNESCO.F90:2
mom_eos_unesco::calculate_density_unesco
Compute the in situ density of sea water (in [kg m-3]), or its anomaly with respect to a reference de...
Definition: MOM_EOS_UNESCO.F90:22