Skip to content

Add optional vertical Coriolis term to hydrostatic pressure integral #4594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

glwagner
Copy link
Member

@glwagner glwagner commented Jun 10, 2025

This PR adds the vertical Coriolis term, z_f_cross_U, to the hydrostatic pressure integral.

I implemented this so that it is optional. This way, the hydrostatic model can use it, but the nonhydrostatic model will not. We don't want to use this for the nonhydrostatic model because we don't always compute the hydrostatic pressure.

I did a bit of housecleaning too.

cc @francispoulin

@simone-silvestri I would like to change the kwarg "parameters" to "kernel_parameters" everywhere in a future PR (just mentioning here since I was looking at it).

Also the kernel parameter functions should not be defined in the same file as the kernels. They should be defined where they are used, eg for each model.

@glwagner glwagner changed the title Add vertical Coriolis to hydrostatic pressure integral Add optional vertical Coriolis term to hydrostatic pressure integral Jun 10, 2025

for k in grid.Nz-1 : -1 : 1
@inbounds pHY′[i, j, k] = pHY′[i, j, k+1] - z_dot_g_bᶜᶜᶠ(i, j, k+1, grid, buoyancy, C) * Δzᶜᶜᶠ(i, j, k+1, grid)
dpdz⁺ = z_dot_g_bᶜᶜᶠ(i, j, k+1, grid, buoyancy, tracers) - z_f_cross_U(i, j, k+1, grid, coriolis, velocities)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This looks great! Does z_f_cross_U need to be defined anywhere or is it already computed?

Copy link
Collaborator

@francispoulin francispoulin left a comment

Choose a reason for hiding this comment

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

This looks good to me and I approve the changes, but I think someone else should too.

To add in the complete Coriolis force we just need to add another body force in the zonal momentum equation. That should be easy enough to do without worrying about whether the methods are energy or enstrophy conserving.

@glwagner
Copy link
Member Author

This looks good to me and I approve the changes, but I think someone else should too.

To add in the complete Coriolis force we just need to add another body force in the zonal momentum equation. That should be easy enough to do without worrying about whether the methods are energy or enstrophy conserving.

why do we need another body force? Isn't this already included in x_cross_U? We already have non-traditional models for example.

You could set up an example with a non-traditional Coroilis in the hydrostatic model to validate this

@glwagner
Copy link
Member Author

for example

@inline x_f_cross_U(i, j, k, grid, coriolis::ConstantCartesianCoriolis, U) = ℑxᶠᵃᵃ(i, j, k, grid, fʸw_minus_fᶻv, coriolis, U)

@inline fʸw_minus_fᶻv(i, j, k, grid, coriolis, U) =
coriolis.fy * ℑzᵃᵃᶜ(i, j, k, grid, U.w) - coriolis.fz * ℑyᵃᶜᵃ(i, j, k, grid, U.v)

this is the complete tangent plane approximation for any background rotation around an arbitrary axis. There is also a non-traditional beta plane.

@francispoulin
Copy link
Collaborator

francispoulin commented Jun 10, 2025

This looks good to me and I approve the changes, but I think someone else should too.
To add in the complete Coriolis force we just need to add another body force in the zonal momentum equation. That should be easy enough to do without worrying about whether the methods are energy or enstrophy conserving.

why do we need another body force? Isn't this already included in x_cross_U? We already have non-traditional models for example.

You could set up an example with a non-traditional Coroilis in the hydrostatic model to validate this

This is probably my misunderstanding. I just meant that in the zonal momentum equation we need a term like

2Ω * cos(latitude) * w

If it's there already, great. If not, it's easy to add it in.

We need this term to cancel the term added into the vertical momentum equation so that energy is conserved.

Maybe it's there already but I didn't see it.

When I look in the spherical Coriolis script, I see that it only computes the sin of the latitude, not the cosine. But this should be easy to copy over from the non-traditional term, as you mentioned.

https://github.com/CliMA/Oceananigans.jl/blob/main/src/Coriolis/hydrostatic_spherical_coriolis.jl

@glwagner
Copy link
Member Author

This is probably my misunderstanding. I just meant that in the zonal momentum equation we need a term like

2Ω * cos(latitude) * w

There are two things going on and I would like to implement them in separate PRs. First, this PR implements a z-component of the Coriolis force which can be used in the hydrostatic model (we already have this for NonhydrostaticModel). This allows us to use Coriolis types that include z-components (as well as an additional zonal component). There are two such types right now --- ConstantCartesianCoriolis and NonTraditionalBetaPlane.

Since we already have these implemented, a simulation that uses these types in HydrostaticFreeSurfaceModel can be used as a validation case for this PR.

There is finally an additional Coriolis type we can add, which includes the full spherical variation of the Coriolis force with latitude in addition to the extra vertical and zonal components of the Coriolis force that do not appear in the typical HydrostaticCoriolisForce.

This second addition is beyond the scope of this PR and should be tackled in another PR.

@glwagner
Copy link
Member Author

Just to clarify further, it is only models on LatitudeLongitudeGrid or OrthogonalSphericalShellGrid that can use a latitude-dependent Coriolis force. But the quasi-hydrostatic approximation has applications on both LatitudeLongitudeGrid and RectilinearGrid. Does that make sense?

@francispoulin
Copy link
Collaborator

Thanks @glwagner for clarifying. I'm happy with these two parts, and am glad we are starting with the easier of the two.

I just want to repeat that if we include the Coriolis term in the vertical equation, so we have hydrostatic balance, we should always make sure to include the other non-traditional term in the zonal momentum equation. If you don't include both your energy balance will be all messed up.

@glwagner
Copy link
Member Author

Thanks @glwagner for clarifying. I'm happy with these two parts, and am glad we are starting with the easier of the two.

I just want to repeat that if we include the Coriolis term in the vertical equation, so we have hydrostatic balance, we should always make sure to include the other non-traditional term in the zonal momentum equation. If you don't include both your energy balance will be all messed up.

But that is guaranteed by every Coriolis implementation. So what is the problem?

@glwagner
Copy link
Member Author

Here are two examples:

HydrostaticSphericalCoriolis

@inline x_f_cross_U(i, j, k, grid, coriolis::CoriolisEnstrophyConserving, U) =
@inbounds - ℑyᵃᶜᵃ(i, j, k, grid, fᶠᶠᵃ, coriolis) *
active_weighted_ℑxyᶠᶜᶜ(i, j, k, grid, Δx_qᶜᶠᶜ, U[2]) * Δx⁻¹ᶠᶜᶜ(i, j, k, grid)

@inline z_f_cross_U(i, j, k, grid, coriolis::HydrostaticSphericalCoriolis, U) = zero(grid)

ConstantCartesianCoriolis

@inline x_f_cross_U(i, j, k, grid, coriolis::ConstantCartesianCoriolis, U) = ℑxᶠᵃᵃ(i, j, k, grid, fʸw_minus_fᶻv, coriolis, U)
@inline y_f_cross_U(i, j, k, grid, coriolis::ConstantCartesianCoriolis, U) = ℑyᵃᶠᵃ(i, j, k, grid, fᶻu_minus_fˣw, coriolis, U)
@inline z_f_cross_U(i, j, k, grid, coriolis::ConstantCartesianCoriolis, U) = ℑzᵃᵃᶠ(i, j, k, grid, fˣv_minus_fʸu, coriolis, U)

@francispoulin can you please state specifically where there is a problem in the code?

@francispoulin
Copy link
Collaborator

Thanks @glwagner for clarifying. I'm happy with these two parts, and am glad we are starting with the easier of the two.
I just want to repeat that if we include the Coriolis term in the vertical equation, so we have hydrostatic balance, we should always make sure to include the other non-traditional term in the zonal momentum equation. If you don't include both your energy balance will be all messed up.

But that is guaranteed by every Coriolis implementation. So what is the problem?

Not a problem, I don't think.

@francispoulin
Copy link
Collaborator

Here are two examples:

HydrostaticSphericalCoriolis

@inline x_f_cross_U(i, j, k, grid, coriolis::CoriolisEnstrophyConserving, U) =
@inbounds - ℑyᵃᶜᵃ(i, j, k, grid, fᶠᶠᵃ, coriolis) *
active_weighted_ℑxyᶠᶜᶜ(i, j, k, grid, Δx_qᶜᶠᶜ, U[2]) * Δx⁻¹ᶠᶜᶜ(i, j, k, grid)

@inline z_f_cross_U(i, j, k, grid, coriolis::HydrostaticSphericalCoriolis, U) = zero(grid)

ConstantCartesianCoriolis

@inline x_f_cross_U(i, j, k, grid, coriolis::ConstantCartesianCoriolis, U) = ℑxᶠᵃᵃ(i, j, k, grid, fʸw_minus_fᶻv, coriolis, U)
@inline y_f_cross_U(i, j, k, grid, coriolis::ConstantCartesianCoriolis, U) = ℑyᵃᶠᵃ(i, j, k, grid, fᶻu_minus_fˣw, coriolis, U)
@inline z_f_cross_U(i, j, k, grid, coriolis::ConstantCartesianCoriolis, U) = ℑzᵃᵃᶠ(i, j, k, grid, fˣv_minus_fʸu, coriolis, U)

@francispoulin can you please state specifically where there is a problem in the code?

In the first term I don't now where we have 2*Omega*cos(phi)*w - 2*Omega*sin(phi)*u terms define. Can you point me to the code that does this?

The second term looks to be correct but I don't know where the terms like fʸw_minus_fᶻv are defined. Can you point me to that as well?

@glwagner
Copy link
Member Author

glwagner commented Jun 12, 2025

In the first term I don't now where we have 2*Omega*cos(phi)*w - 2*Omega*sin(phi)*u terms define. Can you point me to the code that does this?

The HydrostaticSphericalCoriolis is hydrostatic (not quasi-hydrostatic), and therefore does not include the non-traditional term. This is done consistently, so that z_f_cross_U = 0 as well.

To include the second term, we need a new Coriolis type.

In other words, there is no problem now, because there is no Coriolis implementation that includes a vertical component but then inconsistently does NOT include the corresponding zonal term.

Note, there is no where else int he code where Coriolis forces are defined. The entire Coriolis force must be defined through the *_f_cross_U functions.

@francispoulin
Copy link
Collaborator

@glwagner I added a file in examples called linear_shear.jl. It specifies a shear in the zonal velocity both in y and z, which are relatec to fz and fy, respecitvely.

This still needs to be set up to validate that this PR does what it wants, but is this what you were thinking?

It's easy enough to have either the traditional or nontraditional terms, or both. I suppose it would be worth testing what this done on main before the choices?

@francispoulin
Copy link
Collaborator

@glwagner , did you have a chance to look at the file I added into examples? This should not be an example, but it's something we can play with, I think. It specifies a mean velocity in two directions that depend on both components of the Coriolis parameters. I thought this is what you had asked about.

@glwagner
Copy link
Member Author

What's the output of the file? Does it validate the new Coriolis term?

@francispoulin
Copy link
Collaborator

What's the output of the file? Does it validate the new Coriolis term?

No. At the moment it just sets up a thermal wind problem with the traditional and non-traditioinal Coriolis terms. It is using the Cartesian geometry, just as a starting point and will be useful to build from and then for comparison.

I will extend to to a lat-lon grid and see how things work, if they work. I just wanted to check to see if this is what you had in mind first.

I can work on this on Monday or Tuesday for the spherical geometry.

@glwagner
Copy link
Member Author

Does the script run?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants