Skip to content

Baroclinic sea level calculation - #1104

Open
c2xu wants to merge 7 commits into
NOAA-GFDL:dev/gfdlfrom
c2xu:c2xu/bsl2
Open

Baroclinic sea level calculation#1104
c2xu wants to merge 7 commits into
NOAA-GFDL:dev/gfdlfrom
c2xu:c2xu/bsl2

Conversation

@c2xu

@c2xu c2xu commented May 4, 2026

Copy link
Copy Markdown

This replaces PR #984 and is based on algorithms in a manuscript that we plan to submit to JPO. Reference to this work will be added as soon as it's available.

@c2xu
c2xu marked this pull request as draft May 7, 2026 16:30
@c2xu
c2xu force-pushed the c2xu/bsl2 branch 2 times, most recently from 49713c9 to c610d30 Compare May 7, 2026 17:51
@c2xu
c2xu marked this pull request as ready for review May 7, 2026 18:40
@c2xu
c2xu force-pushed the c2xu/bsl2 branch 2 times, most recently from 2aa435f to 0389b19 Compare May 8, 2026 14:19
Comment thread src/core/MOM_interface_heights.F90 Outdated
Comment thread src/core/MOM_interface_heights.F90 Outdated
Comment thread src/core/MOM_interface_heights.F90 Outdated
@c2xu
c2xu force-pushed the c2xu/bsl2 branch 5 times, most recently from d0be54e to 8a56e4e Compare June 9, 2026 15:16
Comment thread src/core/MOM_interface_heights.F90 Outdated
pt, & ! Pressure at the top of a layer [R L2 T-2 ~> Pa]
pb, & ! Pressure at the bottom of a layer [R L2 T-2 ~> Pa]
gz, & ! Geopotential at the bottom of a layer [L2 T-2 ~> m2 s-2]
dp, & ! Pressure change across a layer in Boussinesq mode [R L2 T-2 ~> Pa]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment here should make it clear that this is the anomaly in the pressure change across a layer relative to what would be found if the density of the layer were rho_s. Without this clarification, it is very hard to see how the code in this routine would generate the baroclinic sea level anomaly. This comment also pertains to the descriptions of dg, dp_int, dg_int and p_int in the next few lines, all of which are also anomalies relative to the reference state.

c2xu and others added 5 commits July 18, 2026 22:57
Algorithms implemented in MOM_interface_heights.F90
Implemented in MOM_diagnostics.F90
Implemented for harmonic analysis
* Rewrite algorithm for the EOS and non-Boussinesq case.

* Skip calculations at grid points with potentially zero depth.
* Fix dimensions of variables

* Set the surface density as a run-time parameter, RHO_BSL, with
the default value being RHO_BSL = 1025 kg m-3.

I_gEarth = 1.0 / GV%g_Earth; SpV_s = 1.0 / rho_s

call find_eta(h, tv, G, GV, US, eta, halo_size=1, dZref=dZ_ref)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This call to find_eta is only needed in Boussinesq mode. Because this can be an expensive call in non-Boussinesq mode, it should be avoided when it is not needed. In fact, given the substantial differences in the algorithms and the meanings of the variables between Boussinesq and non-Boussinesq modes, I would be tempted to go so far as to split the body of this routine into two separate routines that are called depending on whether the Boussinsesq approximation is being made.

@Hallberg-NOAA Hallberg-NOAA left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have worked through all of the calculations in this revised PR, and I am convinced that all of the expressions are correct (or at least plausible). The one big thing that would have helped in working through the code is for there to be more explicit comments describing some of the variables in find_bsl() to make it clear that they are anomalies relative to what would be found if the density were RHO_BSL, and that they can be negative. I think that this probably applies to dp, dp_int, and pt in Boussinesq mode while in non-Boussinesq mode it applies to gz, dg, and dg_int and p_int, but not to pb, pt or dp. (Without this reminder in the comments I spent much more time than I should looking for the subtraction without which the calculations do not make sense!) Given the very different meanings of these variables, it might even make sense to refactor find_bsl() to have separate internal routines (with a common top-level interfaces) for the Boussinesq and non-Boussinesq cases.

There also needs to be a more explicit description in the MOM_parameter_doc description for RHO_BSL explaining that this is the reference density for determining the surface height anomalies from on the baroclinic density structure based on integrals of the differences between the actual density and this value.

With these relatively straightforward changes to the documentation in the code and perhaps some strategic refactoring greater clarity (but without changing any of the actual calculations), I think that this PR would be ready to be accepted.

@Hallberg-NOAA Hallberg-NOAA added enhancement New feature or request Parameter change Input parameter changes (addition, removal, or description) labels Jul 19, 2026
Comment thread src/core/MOM_interface_heights.F90 Outdated
enddo
!$OMP do
do j=js,je ; do i=is,ie ; if (maskT(i,j)) then
bsl(i,j) = - (p_int(i,j) * I_gEarth) / (rho_s * bathyT(i,j))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect that there are cases where dividing by bathyT here will not work because in some cases (such as the Great Lakes) bathyT can be equal to or above the reference geoid and still have water. Would it make more sense to use the vertical sum of the layer thicknesses (perhaps in a max with GV%H_subroundoff) in the denominator instead?

Comment thread src/core/MOM_interface_heights.F90 Outdated
enddo
!$OMP do
do j=js,je ; do i=is,ie ; if (maskT(i,j)) then
bsl(i,j) = (p_int(i,j) * (I_gEarth * I_gEarth)) / (rho_s * bathyT(i,j))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the denominator here should be the sum of the layer thicknesses.

Also, there should be spaces around the semicolon on the next line to follow the pattern used elsewhere.

* Clarify the description of local variables in find_bsl(), and the
  description of RHO_BSL in MOM_parameter_doc

* Move find_eta so that it is not called in non-Boussinesq mode
@chengz2

chengz2 commented Jul 20, 2026

Copy link
Copy Markdown

Because whether the Boussinesq mode is activated must be determined during the run time, I feel it's difficult to split this subroutine into multiple subroutines under the same interface.

@chengz2

chengz2 commented Jul 20, 2026

Copy link
Copy Markdown

For BSL calculation, what matters is not whether bathyT is above or below the reference geoid, but where the mean sea level is. The bsl calculation will be incorrect if the mean sea level is non-zero, even if bathyT is below the geoid. bathyT is in fact defined as bathyT(i,j) = G%bathyT(i,j) + dZ_ref. Am I correct that this dZ_ref is a correction to the mean sea level if it's non-zero? If not, is there another variable available in MOM6 that I can use? Or do I have to calculate it manually? Thanks, @Hallberg-NOAA.

@chengz2

chengz2 commented Jul 20, 2026

Copy link
Copy Markdown

For BSL calculation, what matters is not whether bathyT is above or below the reference geoid, but where the mean sea level is. The bsl calculation will be incorrect if the mean sea level is non-zero, even if bathyT is below the geoid. bathyT is in fact defined as bathyT(i,j) = G%bathyT(i,j) + dZ_ref. Am I correct that this dZ_ref is a correction to the mean sea level if it's non-zero? If not, is there another variable available in MOM6 that I can use? Or do I have to calculate it manually? Thanks, @Hallberg-NOAA.

Also, in theory, the denominator should be the distance between the bottom and the mean sea level, instead of the instantaneous sea level, i.e., it should be time-independent. That's another reason I'm trying to avoid using the sum of layer thickness, because if the SSH variation is large relative to the total depth, this will amplify the error.

@c2xu
c2xu requested a review from Hallberg-NOAA July 23, 2026 02:01
@Hallberg-NOAA

Copy link
Copy Markdown
Member

Splitting this subroutine into 3 (one that is called from outside, and a Boussinesq version or a non-Boussinesq version that are called from the first one, depending on whether or not a particular run is Boussinesq) should be straightforward. This is the pattern that was adopted in MOM_PressureForce.F90, although in this case I would keep all 3 subroutines in the same module.

@Hallberg-NOAA

Copy link
Copy Markdown
Member

You can accommodate spatially varying time-mean sea levels by using (G%meanSL(i,j) + G%bathyT(i,j)) in place of G%bathyT(i,j).

However, in the cases here it seems to me that we are dividing an integral by the total depth or pressure to give what amounts to a vertical average. If this can be interpreted as a vertical average, I would think that because the bounds of integration in the numerator vary with the rapid time-scales, the normalization in the denominator should also exhibit the same rapid variations.

@c2xu

c2xu commented Jul 29, 2026

Copy link
Copy Markdown
Author

Splitting this subroutine into 3 (one that is called from outside, and a Boussinesq version or a non-Boussinesq version that are called from the first one, depending on whether or not a particular run is Boussinesq) should be straightforward. This is the pattern that was adopted in MOM_PressureForce.F90, although in this case I would keep all 3 subroutines in the same module.

find_bsl() is split into three subroutines as requested.

Split find_bsl() into three subroutines, depending on whether an
equation of state is used and whether the Boussinesq approximation
is used.
@c2xu

c2xu commented Jul 29, 2026

Copy link
Copy Markdown
Author

You can accommodate spatially varying time-mean sea levels by using (G%meanSL(i,j) + G%bathyT(i,j)) in place of G%bathyT(i,j).

However, in the cases here it seems to me that we are dividing an integral by the total depth or pressure to give what amounts to a vertical average. If this can be interpreted as a vertical average, I would think that because the bounds of integration in the numerator vary with the rapid time-scales, the normalization in the denominator should also exhibit the same rapid variations.

I thought about it and decided not to make this change for the following reasons:

  1. Barotropic-baroclinic sea level decomposition is likely to be useful only in the deep ocean where baroclinic internal waves are "large", yielding sea level fluctuations of a few cm. I don't think it should ever be calculated at locations such as the Great Lakes.

  2. In the deep ocean, mean sea level fluctuations relative to the total depth is on the order of $10^{-3}$, so I don't think it is necessary to replace G%bathyT(i,j) by (G%meanSL(i,j) + G%bathyT(i,j)) in the denominator.

  3. This is perhaps the most confusing part: In theory, the denominator, as well as the upper limit of integration, should not consist of temporal variation of the sea level, because this calculation is based on the linear decomposition of the sea level, and the baroclinic sea level is an anomaly to the mean state around which the dynamics are linearized. Introducing temporal dependency to the denominator will introduce a nonlinearity that breaks this linear decomposition. But again, because the temporal variation of the sea level relative to the total depth is on the order of $10^{-3}$, whether or not including this temporal variation in the denominator should not change the answer in the deep ocean in any significant way.

  4. That said, the temporal varying, instantaneous sea level, instead of the mean sea level, is used as the upper limit of integration in this algorithm. This is not a problem in general because the density difference between the mean sea level and the instantaneous sea level, if any, should be negligible. Because we use surface density as the reference density, the density anomaly at the surface is essentially zero. Hence, the vertical integral of this density anomaly between the mean sea level and the instantaneous sea level should also be negligible.

I've added some comments explaining some of these aspects in the code. A more complete, mathematically rigours explanation of this algorithm, and the physics behind it, will be available once our paper is published.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request Parameter change Input parameter changes (addition, removal, or description)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants