Skip to content

Commit ed4623b

Browse files
Hallberg-NOAAmarshallward
authored andcommitted
*Refactor calculate_specific_vol_wright_full
Refactored the specific volume calculations for the WRIGHT_FULL and WRIGHT_RED equations of states for simplicity or to reduce the impacts of roundoff when removing a reference value. Also added code to multiply by the reciprocal of the denominator rather than dividing in several places in the int_spec_vol_dp routines for these same two equations of state, both for efficiency and greater consistency across optimization levels. These changes are mathematically equivalent but will change answers at roundoff with these two equations of state, but they are so new that they can not have been used yet.
1 parent 3731c27 commit ed4623b

File tree

2 files changed

+64
-36
lines changed

2 files changed

+64
-36
lines changed

src/equation_of_state/MOM_EOS_Wright_full.F90

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -179,20 +179,30 @@ subroutine calculate_spec_vol_array_wright(T, S, pressure, specvol, start, npts,
179179
! Local variables
180180
real :: al0 ! The specific volume at 0 lambda in the Wright EOS [m3 kg-1]
181181
real :: p0 ! The pressure offset in the Wright EOS [Pa]
182-
real :: lambda ! The sound speed squared at 0 alpha in the Wright EOS [m2 s-2]
182+
real :: lambda ! The sound speed squared at 0 alpha in the Wright EOS [m2 s-2], perhaps with
183+
! an offset to account for spv_ref
184+
real :: al_TS ! The contributions of temperature and salinity to al0 [m3 kg-1]
185+
real :: p_TSp ! A combination of the pressure and the temperature and salinity contributions to p0 [Pa]
186+
real :: lam_000 ! A corrected offset to lambda, including contributions from spv_ref [m2 s-2]
183187
integer :: j
184188

185-
do j=start,start+npts-1
186-
al0 = a0 + (a1*T(j) + a2*S(j))
187-
p0 = b0 + ( b4*S(j) + T(j) * (b1 + (T(j)*(b2 + b3*T(j)) + b5*S(j))) )
188-
lambda = c0 + ( c4*S(j) + T(j) * (c1 + (T(j)*(c2 + c3*T(j)) + c5*S(j))) )
189-
190-
if (present(spv_ref)) then
191-
specvol(j) = (lambda + (al0 - spv_ref)*(pressure(j) + p0)) / (pressure(j) + p0)
192-
else
193-
specvol(j) = (lambda + al0*(pressure(j) + p0)) / (pressure(j) + p0)
194-
endif
195-
enddo
189+
if (present(spv_ref)) then
190+
lam_000 = c0 + (a0 - spv_ref)*b0
191+
do j=start,start+npts-1
192+
al_TS = a1*T(j) + a2*S(j)
193+
p_TSp = pressure(j) + (b4*S(j) + T(j) * (b1 + (T(j)*(b2 + b3*T(j)) + b5*S(j))))
194+
lambda = lam_000 + ( c4*S(j) + T(j) * (c1 + (T(j)*(c2 + c3*T(j)) + c5*S(j))) )
195+
! This is equivalent to the expression below minus spv_ref, but less sensitive to roundoff.
196+
specvol(j) = al_TS + (lambda + (a0 - spv_ref)*p_TSp) / (b0 + p_TSp)
197+
enddo
198+
else
199+
do j=start,start+npts-1
200+
al0 = a0 + (a1*T(j) + a2*S(j))
201+
p0 = b0 + ( b4*S(j) + T(j) * (b1 + (T(j)*(b2 + b3*T(j)) + b5*S(j))) )
202+
lambda = c0 + ( c4*S(j) + T(j) * (c1 + (T(j)*(c2 + c3*T(j)) + c5*S(j))) )
203+
specvol(j) = al0 + lambda / (pressure(j) + p0)
204+
enddo
205+
endif
196206
end subroutine calculate_spec_vol_array_wright
197207

198208
!> Return the thermal/haline expansion coefficients for 1-d array inputs and outputs
@@ -793,6 +803,7 @@ subroutine int_spec_vol_dp_wright_full(T, S, p_t, p_b, spv_ref, HI, dza, &
793803
real :: hWght ! A pressure-thickness below topography [R L2 T-2 ~> Pa].
794804
real :: hL, hR ! Pressure-thicknesses of the columns to the left and right [R L2 T-2 ~> Pa].
795805
real :: iDenom ! The inverse of the denominator in the weights [T4 R-2 L-4 ~> Pa-2].
806+
real :: I_pterm ! The inverse of p0 plus p_ave [T2 R-1 L-2 ~> Pa-1].
796807
real :: hWt_LL, hWt_LR ! hWt_LA is the weighted influence of A on the left column [nondim].
797808
real :: hWt_RL, hWt_RR ! hWt_RA is the weighted influence of A on the right column [nondim].
798809
real :: wt_L, wt_R ! The linear weights of the left and right columns [nondim].
@@ -866,9 +877,10 @@ subroutine int_spec_vol_dp_wright_full(T, S, p_t, p_b, spv_ref, HI, dza, &
866877
al0 = al0_2d(i,j) ; p0 = p0_2d(i,j) ; lambda = lambda_2d(i,j)
867878
dp = p_b(i,j) - p_t(i,j)
868879
p_ave = 0.5*(p_t(i,j)+p_b(i,j))
880+
I_pterm = 1.0 / (p0 + p_ave)
869881

870-
eps = 0.5 * dp / (p0 + p_ave) ; eps2 = eps*eps
871-
alpha_anom = (al0 - spv_ref) + lambda / (p0 + p_ave)
882+
eps = 0.5 * dp * I_pterm ; eps2 = eps*eps
883+
alpha_anom = (al0 - spv_ref) + lambda * I_pterm
872884
rem = (lambda * eps2) * (C1_3 + eps2*(0.2 + eps2*(C1_7 + C1_9*eps2)))
873885
dza(i,j) = alpha_anom*dp + 2.0*eps*rem
874886
if (present(intp_dza)) &
@@ -906,9 +918,10 @@ subroutine int_spec_vol_dp_wright_full(T, S, p_t, p_b, spv_ref, HI, dza, &
906918

907919
dp = wt_L*(p_b(i,j) - p_t(i,j)) + wt_R*(p_b(i+1,j) - p_t(i+1,j))
908920
p_ave = 0.5*(wt_L*(p_t(i,j)+p_b(i,j)) + wt_R*(p_t(i+1,j)+p_b(i+1,j)))
921+
I_pterm = 1.0 / (p0 + p_ave)
909922

910-
eps = 0.5 * dp / (p0 + p_ave) ; eps2 = eps*eps
911-
intp(m) = ((al0 - spv_ref) + lambda / (p0 + p_ave))*dp + 2.0*eps* &
923+
eps = 0.5 * dp * I_pterm ; eps2 = eps*eps
924+
intp(m) = ((al0 - spv_ref) + lambda * I_pterm)*dp + 2.0*eps* &
912925
lambda * eps2 * (C1_3 + eps2*(0.2 + eps2*(C1_7 + C1_9*eps2)))
913926
enddo
914927
! Use Boole's rule to integrate the values.
@@ -947,9 +960,10 @@ subroutine int_spec_vol_dp_wright_full(T, S, p_t, p_b, spv_ref, HI, dza, &
947960

948961
dp = wt_L*(p_b(i,j) - p_t(i,j)) + wt_R*(p_b(i,j+1) - p_t(i,j+1))
949962
p_ave = 0.5*(wt_L*(p_t(i,j)+p_b(i,j)) + wt_R*(p_t(i,j+1)+p_b(i,j+1)))
963+
I_pterm = 1.0 / (p0 + p_ave)
950964

951-
eps = 0.5 * dp / (p0 + p_ave) ; eps2 = eps*eps
952-
intp(m) = ((al0 - spv_ref) + lambda / (p0 + p_ave))*dp + 2.0*eps* &
965+
eps = 0.5 * dp * I_pterm ; eps2 = eps*eps
966+
intp(m) = ((al0 - spv_ref) + lambda * I_pterm)*dp + 2.0*eps* &
953967
lambda * eps2 * (C1_3 + eps2*(0.2 + eps2*(C1_7 + C1_9*eps2)))
954968
enddo
955969
! Use Boole's rule to integrate the values.

src/equation_of_state/MOM_EOS_Wright_red.F90

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -179,20 +179,30 @@ subroutine calculate_spec_vol_array_wright(T, S, pressure, specvol, start, npts,
179179
! Local variables
180180
real :: al0 ! The specific volume at 0 lambda in the Wright EOS [m3 kg-1]
181181
real :: p0 ! The pressure offset in the Wright EOS [Pa]
182-
real :: lambda ! The sound speed squared at 0 alpha in the Wright EOS [m2 s-2]
182+
real :: lambda ! The sound speed squared at 0 alpha in the Wright EOS [m2 s-2], perhaps with
183+
! an offset to account for spv_ref
184+
real :: al_TS ! The contributions of temperature and salinity to al0 [m3 kg-1]
185+
real :: p_TSp ! A combination of the pressure and the temperature and salinity contributions to p0 [Pa]
186+
real :: lam_000 ! A corrected offset to lambda, including contributions from spv_ref [m2 s-2]
183187
integer :: j
184188

185-
do j=start,start+npts-1
186-
al0 = a0 + (a1*T(j) + a2*S(j))
187-
p0 = b0 + ( b4*S(j) + T(j) * (b1 + (T(j)*(b2 + b3*T(j)) + b5*S(j))) )
188-
lambda = c0 + ( c4*S(j) + T(j) * (c1 + (T(j)*(c2 + c3*T(j)) + c5*S(j))) )
189-
190-
if (present(spv_ref)) then
191-
specvol(j) = (lambda + (al0 - spv_ref)*(pressure(j) + p0)) / (pressure(j) + p0)
192-
else
193-
specvol(j) = (lambda + al0*(pressure(j) + p0)) / (pressure(j) + p0)
194-
endif
195-
enddo
189+
if (present(spv_ref)) then
190+
lam_000 = c0 + (a0 - spv_ref)*b0
191+
do j=start,start+npts-1
192+
al_TS = a1*T(j) + a2*S(j)
193+
p_TSp = pressure(j) + (b4*S(j) + T(j) * (b1 + (T(j)*(b2 + b3*T(j)) + b5*S(j))))
194+
lambda = lam_000 + ( c4*S(j) + T(j) * (c1 + (T(j)*(c2 + c3*T(j)) + c5*S(j))) )
195+
! This is equivalent to the expression below minus spv_ref, but less sensitive to roundoff.
196+
specvol(j) = al_TS + (lambda + (a0 - spv_ref)*p_TSp) / (b0 + p_TSp)
197+
enddo
198+
else
199+
do j=start,start+npts-1
200+
al0 = a0 + (a1*T(j) + a2*S(j))
201+
p0 = b0 + ( b4*S(j) + T(j) * (b1 + (T(j)*(b2 + b3*T(j)) + b5*S(j))) )
202+
lambda = c0 + ( c4*S(j) + T(j) * (c1 + (T(j)*(c2 + c3*T(j)) + c5*S(j))) )
203+
specvol(j) = al0 + lambda / (pressure(j) + p0)
204+
enddo
205+
endif
196206
end subroutine calculate_spec_vol_array_wright
197207

198208
!> Return the thermal/haline expansion coefficients for 1-d array inputs and outputs
@@ -793,6 +803,7 @@ subroutine int_spec_vol_dp_wright_red(T, S, p_t, p_b, spv_ref, HI, dza, &
793803
real :: hWght ! A pressure-thickness below topography [R L2 T-2 ~> Pa].
794804
real :: hL, hR ! Pressure-thicknesses of the columns to the left and right [R L2 T-2 ~> Pa].
795805
real :: iDenom ! The inverse of the denominator in the weights [T4 R-2 L-4 ~> Pa-2].
806+
real :: I_pterm ! The inverse of p0 plus p_ave [T2 R-1 L-2 ~> Pa-1].
796807
real :: hWt_LL, hWt_LR ! hWt_LA is the weighted influence of A on the left column [nondim].
797808
real :: hWt_RL, hWt_RR ! hWt_RA is the weighted influence of A on the right column [nondim].
798809
real :: wt_L, wt_R ! The linear weights of the left and right columns [nondim].
@@ -866,9 +877,10 @@ subroutine int_spec_vol_dp_wright_red(T, S, p_t, p_b, spv_ref, HI, dza, &
866877
al0 = al0_2d(i,j) ; p0 = p0_2d(i,j) ; lambda = lambda_2d(i,j)
867878
dp = p_b(i,j) - p_t(i,j)
868879
p_ave = 0.5*(p_t(i,j)+p_b(i,j))
880+
I_pterm = 1.0 / (p0 + p_ave)
869881

870-
eps = 0.5 * dp / (p0 + p_ave) ; eps2 = eps*eps
871-
alpha_anom = (al0 - spv_ref) + lambda / (p0 + p_ave)
882+
eps = 0.5 * dp * I_pterm ; eps2 = eps*eps
883+
alpha_anom = (al0 - spv_ref) + lambda * I_pterm
872884
rem = (lambda * eps2) * (C1_3 + eps2*(0.2 + eps2*(C1_7 + C1_9*eps2)))
873885
dza(i,j) = alpha_anom*dp + 2.0*eps*rem
874886
if (present(intp_dza)) &
@@ -906,9 +918,10 @@ subroutine int_spec_vol_dp_wright_red(T, S, p_t, p_b, spv_ref, HI, dza, &
906918

907919
dp = wt_L*(p_b(i,j) - p_t(i,j)) + wt_R*(p_b(i+1,j) - p_t(i+1,j))
908920
p_ave = 0.5*(wt_L*(p_t(i,j)+p_b(i,j)) + wt_R*(p_t(i+1,j)+p_b(i+1,j)))
921+
I_pterm = 1.0 / (p0 + p_ave)
909922

910-
eps = 0.5 * dp / (p0 + p_ave) ; eps2 = eps*eps
911-
intp(m) = ((al0 - spv_ref) + lambda / (p0 + p_ave))*dp + 2.0*eps* &
923+
eps = 0.5 * dp * I_pterm ; eps2 = eps*eps
924+
intp(m) = ((al0 - spv_ref) + lambda * I_pterm)*dp + 2.0*eps* &
912925
lambda * eps2 * (C1_3 + eps2*(0.2 + eps2*(C1_7 + C1_9*eps2)))
913926
enddo
914927
! Use Boole's rule to integrate the values.
@@ -947,9 +960,10 @@ subroutine int_spec_vol_dp_wright_red(T, S, p_t, p_b, spv_ref, HI, dza, &
947960

948961
dp = wt_L*(p_b(i,j) - p_t(i,j)) + wt_R*(p_b(i,j+1) - p_t(i,j+1))
949962
p_ave = 0.5*(wt_L*(p_t(i,j)+p_b(i,j)) + wt_R*(p_t(i,j+1)+p_b(i,j+1)))
963+
I_pterm = 1.0 / (p0 + p_ave)
950964

951-
eps = 0.5 * dp / (p0 + p_ave) ; eps2 = eps*eps
952-
intp(m) = ((al0 - spv_ref) + lambda / (p0 + p_ave))*dp + 2.0*eps* &
965+
eps = 0.5 * dp * I_pterm ; eps2 = eps*eps
966+
intp(m) = ((al0 - spv_ref) + lambda * I_pterm)*dp + 2.0*eps* &
953967
lambda * eps2 * (C1_3 + eps2*(0.2 + eps2*(C1_7 + C1_9*eps2)))
954968
enddo
955969
! Use Boole's rule to integrate the values.

0 commit comments

Comments
 (0)