From 5d405ad53824609642835cd02f3be158ad0e544b Mon Sep 17 00:00:00 2001 From: Andrew Barna Date: Wed, 20 Aug 2025 18:27:22 -0700 Subject: [PATCH 1/5] Add geo_strf_steric_height function --- gsw/geostrophy.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/gsw/geostrophy.py b/gsw/geostrophy.py index 501f01e..59a410a 100644 --- a/gsw/geostrophy.py +++ b/gsw/geostrophy.py @@ -9,6 +9,7 @@ from .conversions import z_from_p __all__ = ['geo_strf_dyn_height', + 'geo_strf_steric_height', 'distance', 'f', 'geostrophic_velocity', @@ -105,6 +106,42 @@ def geo_strf_dyn_height(SA, CT, p, p_ref=0, axis=0, max_dp=1.0, return dh +@match_args_return +def geo_strf_steric_height(SA, CT, p, p_ref=0, axis=0, max_dp=1.0, interp_method="pchip"): + """ + Steric height anomaly as a function of pressure. + + Parameters + ---------- + SA : array-like + Absolute Salinity, g/kg + CT : array-like + Conservative Temperature (ITS-90), degrees C + p : array-like + Sea pressure (absolute pressure minus 10.1325 dbar), dbar + p_ref : float or array-like, optional + Reference pressure, dbar + axis : int, optional, default is 0 + The index of the pressure dimension in SA and CT. + max_dp : float + If any pressure interval in the input p exceeds max_dp, the dynamic + height will be calculated after interpolating to a grid with this + spacing. + interp_method : string {'mrst', 'pchip', 'linear'} + Interpolation algorithm. + + Returns + ------- + steric_height : array + Dynamic height anomaly divided by the acceleration of gravity. + + """ + return ( + geo_strf_dyn_height(SA, CT, p, p_ref, axis=axis, max_dp=max_dp, interp_method=interp_method) + / 9.7963 + ) + + def unwrap(lon, centered=True, copy=True): """ Unwrap a sequence of longitudes or headings in degrees. From f06ea4441e76fa5161c79396601a10ca1ffce5bd Mon Sep 17 00:00:00 2001 From: Andrew Barna Date: Thu, 21 Aug 2025 16:39:51 -0700 Subject: [PATCH 2/5] add geo_strf_steric_height tests --- gsw/tests/geo_strf_steric_height.npy | Bin 0 -> 1208 bytes gsw/tests/test_check_functions.py | 1 + gsw/tests/test_xarray.py | 1 + gsw/tests/write_geo_npyfiles.py | 6 ++++++ 4 files changed, 8 insertions(+) create mode 100644 gsw/tests/geo_strf_steric_height.npy diff --git a/gsw/tests/geo_strf_steric_height.npy b/gsw/tests/geo_strf_steric_height.npy new file mode 100644 index 0000000000000000000000000000000000000000..be24cf028208bc36a1c56522bb92f514694f6bab GIT binary patch literal 1208 zcmbW!ZBP?*90%}iFku4*lSC@8>2bGsI-7t;ffN`_Q;`gW@gRqL&`uK>oU83N?lK-s ziDDS*q;uy%5d^`;%*&JCKNv6(0k`M@o5$FL2V1y_$rw(u>-zJmH+|pzKKFg|y`MZg z??4WRNH{}~FnRn+u8{c}gPAHwX2vm?f^uP%uI+q23}R`Q>DFv2GwmC%TV zaiO1l>y<_9jE`e7qLoWjryp6&}XQdoyHi?8ZBV zl2DcxEW4_?A?_9I&PeA+l=`O-@hEp?ykHf3=$o9-cHJ6`3If|KZBMX&*J(KQKtezc z_K{VE*^AwEZ?GzsLPSZQRCUGB*078AzHrgrNJQtSvffSKL_q)kWi2ggOEZmxzNHo2 zy!^$w-%Db}f4|cQeZEvNU>PUkzL_feBQnz$afDGNCrl*l;kDr(My8X|!Ft*(Va^A; zD&vRhM%D%t=+rlD{M8q`fZjs4hx;KOH$f4sC1dZAz13j#_#u|dx~=A$4cL<{ie1WI z{EKRk$>!ju#`o??s?sClv5IbB0i&v z_j}j9u$Py_-Vum4<}V-29i-xZ&zP8U$v+5@f9yLvS`&cXZ2a_TvoQ!=Y3B}gumiDg z-t*OIjf#f0vt>u3DM8rtbn^U)+F*1oFEZDnTleZ=hqNv}1ht;eD>l{BaNiWKcLcYD dplkDeBx6=E_Mzg6?Fs@Nnci5~8b=Dj{ufUp?|1+J literal 0 HcmV?d00001 diff --git a/gsw/tests/test_check_functions.py b/gsw/tests/test_check_functions.py index f9166c7..2cf0c6c 100644 --- a/gsw/tests/test_check_functions.py +++ b/gsw/tests/test_check_functions.py @@ -33,6 +33,7 @@ # Substitute new check values for the pchip interpolation version. cv.geo_strf_dyn_height = np.load(os.path.join(root_path,'geo_strf_dyn_height.npy')) +cv.geo_strf_steric_height = np.load(os.path.join(root_path,'geo_strf_steric_height.npy')) cv.geo_strf_velocity = np.load(os.path.join(root_path,'geo_strf_velocity.npy')) cf = Bunch() diff --git a/gsw/tests/test_xarray.py b/gsw/tests/test_xarray.py index 431fd75..2a76e3a 100644 --- a/gsw/tests/test_xarray.py +++ b/gsw/tests/test_xarray.py @@ -42,6 +42,7 @@ # Substitute new check values for the pchip interpolation version. cv.geo_strf_dyn_height = np.load(os.path.join(root_path,'geo_strf_dyn_height.npy')) +cv.geo_strf_steric_height = np.load(os.path.join(root_path,'geo_strf_steric_height.npy')) cv.geo_strf_velocity = np.load(os.path.join(root_path,'geo_strf_velocity.npy')) for name in ['SA_chck_cast', 't_chck_cast', 'p_chck_cast']: diff --git a/gsw/tests/write_geo_npyfiles.py b/gsw/tests/write_geo_npyfiles.py index d91e72d..d816b37 100644 --- a/gsw/tests/write_geo_npyfiles.py +++ b/gsw/tests/write_geo_npyfiles.py @@ -25,6 +25,12 @@ cv.pr) np.save('geo_strf_dyn_height.npy', dyn_height) +steric_height = gsw.geo_strf_steric_height(cv.SA_chck_cast, + cv.CT_chck_cast, + cv.p_chck_cast, + cv.pr) +np.save('geo_strf_steric_height.npy', steric_height) + lon = cv.long_chck_cast lat = cv.lat_chck_cast p = cv.p_chck_cast From fa9d65ffd1d6c8ad79427bf00d3f7b66d1513776 Mon Sep 17 00:00:00 2001 From: Andrew Barna Date: Fri, 22 Aug 2025 12:56:05 -0700 Subject: [PATCH 3/5] add test_steric_height_mrst to test steric height using the MRST-PCHIP interpolation method --- gsw/tests/test_geostrophy.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gsw/tests/test_geostrophy.py b/gsw/tests/test_geostrophy.py index e0d4423..8d69bb6 100644 --- a/gsw/tests/test_geostrophy.py +++ b/gsw/tests/test_geostrophy.py @@ -113,3 +113,15 @@ def test_dyn_height_mrst(): strf = gsw.geo_strf_dyn_height(SA, CT, p, p_ref=pr, interp_method='mrst') assert_allclose(strf, cv.geo_strf_dyn_height, rtol=0, atol=cv.geo_strf_dyn_height_ca) + +def test_steric_height_mrst(): + """ + Tests the MRST-PCHIP interpolation method. + """ + p = cv.p_chck_cast + CT = cv.CT_chck_cast + SA = cv.SA_chck_cast + pr = cv.pr + strf = gsw.geo_strf_steric_height(SA, CT, p, p_ref=pr, interp_method='mrst') + + assert_allclose(strf, cv.geo_strf_steric_height, rtol=0, atol=cv.geo_strf_steric_height_ca) \ No newline at end of file From 9548e7f5d999469d3b41111afbd1503d97775695 Mon Sep 17 00:00:00 2001 From: Andrew Barna Date: Fri, 22 Aug 2025 13:13:05 -0700 Subject: [PATCH 4/5] improve geo_strf_steric_height docstring --- gsw/geostrophy.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gsw/geostrophy.py b/gsw/geostrophy.py index 59a410a..c830911 100644 --- a/gsw/geostrophy.py +++ b/gsw/geostrophy.py @@ -133,7 +133,12 @@ def geo_strf_steric_height(SA, CT, p, p_ref=0, axis=0, max_dp=1.0, interp_method Returns ------- steric_height : array - Dynamic height anomaly divided by the acceleration of gravity. + This is the integral of specific volume anomaly with respect + to pressure, from each pressure in p to the specified + reference pressure divided by the constant value of the gravitational + acceleration, 9.7963 m s^-2. It is not exactly the height of an + isobaric surface above a geopotential surface, but is an exact + geostrophic streamfunction. """ return ( From 5116ea3b9e6a27e8d46fdca15e97cf269538ccc3 Mon Sep 17 00:00:00 2001 From: Andrew Barna Date: Fri, 22 Aug 2025 20:54:06 -0700 Subject: [PATCH 5/5] add reference to geo_strf_steric_height --- gsw/geostrophy.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gsw/geostrophy.py b/gsw/geostrophy.py index c830911..ac0c2dc 100644 --- a/gsw/geostrophy.py +++ b/gsw/geostrophy.py @@ -135,10 +135,15 @@ def geo_strf_steric_height(SA, CT, p, p_ref=0, axis=0, max_dp=1.0, interp_method steric_height : array This is the integral of specific volume anomaly with respect to pressure, from each pressure in p to the specified - reference pressure divided by the constant value of the gravitational - acceleration, 9.7963 m s^-2. It is not exactly the height of an - isobaric surface above a geopotential surface, but is an exact - geostrophic streamfunction. + reference pressure, divided by the global mean surface value of + gravitational acceleration, 9.7963 m s^-2. (see page 46 of Griffies, 2004) + It is not exactly the height of an isobaric surface above a + geopotential surface, but is an exact geostrophic streamfunction. + + References + ---------- + Griffies, S. M., 2004: Fundamentals of Ocean Climate Models. Princeton, + NJ: Princeton University Press, 518 pp + xxxiv. """ return (