-
Notifications
You must be signed in to change notification settings - Fork 201
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
Allow divergent Lagrangian-mean velocity by subtracting Stokes drift before pressure correction #4013
base: main
Are you sure you want to change the base?
Conversation
…before pressure correction
@BrodiePearson @qingli411 tagging you two because you may be interested in this. I think if we want to move forward with this, possibly we should change the interface for using Thoughts? |
Yes, I think asking users to provide the Stokes drift itself sounds good as it allows more flexibility and we can also make sure the derivatives are consistent. One minor point I can think of is that, is there a way to do the derivatives analytically in the code then evaluate their values at appropriate locations, or we will need to evaluate Stokes drift first then do the derivatives numerically? Probably doesn't matter except very close to the surface? |
In principle we can use automatic differentiation to compute analytical derivatives. But I don't know if we want to bake that kind of thing into the code. Now I am thinking, maybe its nice to allow the derivatives to be specified analytically, but we can add a feature whereby they are computed from the Stokes drift in the case they aren't provided. So then both cases are supported. |
Also I am not sure what is the "right" thing to do in this case. For example if we want to compute a finite volume approximation to where The same argument can be used for |
Okay, my new idea is actually to stop supporting specifying derivatives because it looks like computing things directly from |
I agree with this approach (specify Stokes drift and then compute relevant derivatives via finite-difference methods - rather than supplying all the derivatives). Since the wave-averaged forces are body forces, it seems your example above often provides the exact derivative needed. There would be some error if the Stokes drift varies horizontally. Even in this case, the errors would presumably be less than the current method of specifying local derivatives to be applied within a volume-averaged equation set. |
So should we specify the cell-averaged Stokes drift or Stokes drift at the cell center? |
@qingli411 I think the Stokes drift would be specified as an analytical function |
u[i, j, k] = u[i, j, k] + sgn * sd.uˢ(Xu..., time, pt...) | ||
v[i, j, k] = v[i, j, k] + sgn * sd.vˢ(Xv..., time, pt...) | ||
w[i, j, k] = w[i, j, k] + sgn * sd.wˢ(Xw..., time, pt...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this subtracting/adding the Stokes drift at a specific depth from a depth-averaged current? Perhaps this is the kind of issue you were alluding to @qingli411
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think here we should use cell-averaged Stokes drift and in the finite volume approximation of
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, it's a good idea to discuss the discretization. I think on a C-grid we probably want to have the Stokes drift at the same location as the velocity components. This would not be cell centers, but Face, Center, Center for u^S, Center, Face, Center for v^S, etc.
Probably, there is a correct discretization of the term
For example see how we do it for Coriolis on the sphere:
Oceananigans.jl/src/Coriolis/hydrostatic_spherical_coriolis.jl
Lines 112 to 119 in d8273e7
@inline f_ℑx_vᶠᶠᵃ(i, j, k, grid, coriolis, v) = fᶠᶠᵃ(i, j, k, grid, coriolis) * ℑxᶠᵃᵃ(i, j, k, grid, Δx_qᶜᶠᶜ, v) | |
@inline f_ℑy_uᶠᶠᵃ(i, j, k, grid, coriolis, u) = fᶠᶠᵃ(i, j, k, grid, coriolis) * ℑyᵃᶠᵃ(i, j, k, grid, Δy_qᶠᶜᶜ, u) | |
@inline x_f_cross_U(i, j, k, grid, coriolis::CoriolisEnergyConserving, U) = | |
@inbounds - ℑyᵃᶜᵃ(i, j, k, grid, f_ℑx_vᶠᶠᵃ, coriolis, U[2]) / Δxᶠᶜᶜ(i, j, k, grid) | |
@inline y_f_cross_U(i, j, k, grid, coriolis::CoriolisEnergyConserving, U) = | |
@inbounds + ℑxᶜᵃᵃ(i, j, k, grid, f_ℑy_uᶠᶠᵃ, coriolis, U[1]) / Δyᶜᶠᶜ(i, j, k, grid) |
If we want to be able to naturally compute
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can build a simple example to demonstrate conservation of energy (which is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But what I'm not sure about is that, if the Stokes drift cannot be specified as an analytical function, what values should we pass in? So maybe also keep the option to pass in the derivatives of Stokes drift?
That's a fair point. Though it would still be possible to compute the Stokes drift numerically by integrating its derivatives, but maybe that's not so convenient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But what I'm not sure about is that, if the Stokes drift cannot be specified as an analytical function, what values should we pass in? So maybe also keep the option to pass in the derivatives of Stokes drift?
That's a fair point. Though it would still be possible to compute the Stokes drift numerically by integrating its derivatives, but maybe that's not so convenient.
The pressure solver depends only on the divergence of the velocity field. If the Stokes drift gradients were provided, would we now need to specify every derivative since the terms needed for the pressure solver Eulerian-ization (
Oceananigans.jl/src/StokesDrifts.jl
Lines 153 to 167 in 0fc5708
struct StokesDrift{P, US, VS, WS, VX, WX, UY, WY, UZ, VZ, UT, VT, WT} | |
uˢ :: US | |
vˢ :: VS | |
wˢ :: WS | |
∂x_vˢ :: VX | |
∂x_wˢ :: WX | |
∂y_uˢ :: UY | |
∂y_wˢ :: WY | |
∂z_uˢ :: UZ | |
∂z_vˢ :: VZ | |
∂t_uˢ :: UT | |
∂t_vˢ :: VT | |
∂t_wˢ :: WT | |
parameters :: P | |
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. Maybe asking the users to specify every derivative is too complicated. I agree that the easiest approach is to specify the Stokes drift as
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe asking the users to specify every derivative is too complicated.
It's what we do currently 😂
We don't have to choose to do anything specific. We can keep the existing structure, and add a new one wherein users specify the Stokes drift only. Then the test of time shall arbitrate.
Mainly I think it could save us time and effort in the end to have just one implementation. Then we know that we are all using the same code and more likely to find bugs / benefit from improvements together.
The difference between the Stokes drift at a specific depth and a depth-averaged Stokes drift around that depth should be small if we have sufficient resolution.
I do think that either way, sufficient resolution renders either discretization similar. But it would be interesting to understand the implications of inadequate resolution too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think as @BrodiePearson pointed out we will need to specify three more spatial derivatives (
I agree. I was not saying we should ignore the differences. But I cannot think of a clean way to specify the Stokes drift. I think we need both the Stokes drift at a specific depth and the depth-averaged Stokes drift around that depth. Maybe asking users to specify both is another option? I was also thinking of an option to specify the wave spectrum, or a simplified one with less frequency bins as Brandon did in MOM6. But maybe these different options can be wrapped into another layer of interface in the StokesDrift module, or defined by users. Internally in Oceananigans, I guess we need
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can compute the finite volume derivatives of the Stokes drift field in the same way that we compute the discrete finite volume derivatives of the prognostic velocity field. The simplest stencil is second-order accurate (it looks just like a finite difference stencil). You could be right though that the derivatives may be known with higher accuracy if users are allowed to supply them.
It wouldn't be too much work to put an interface where the needed derivatives may be optionally provided, and otherwise are computed with a finite volume method.
Typo w -> v
This is a good discussion, but I think I am falling into a rabbit hole. I am swinging towards @qingli411 's suggestion of the optimal solution being to specify both the Stokes drift at specific depths and the depth-averaged Stokes drift for the following reasons:
This got me thinking more about discretization/finite-volume errors in traditional (Eulerian) LES and Oceananigans.
|
A few preliminary thoughts: if you have a function that computes the Stokes drift, you can (if you want) also compute or pre-compute the depth-average of that field. So for Stokes drift from functions I don't know if we would ever need anything more than Stokes drift; we can compute volume averaged derivatives and volume-averaged Stokes drift from the function, if needed. But also note that throughout the code --- for initial conditions, forcing, and boundary conditions --- we always approximate volume-averages of functions by evaluating the function in the middle of the cell. There is an issue somewhere about using more accurate quadrature but nobody has found a need for it, it would seem, so it isn't implemented... I think we should start with something simple and build up more features / more accurate approximations as needed (eg if someone would like to test the impact of an approximation and write a paper about it, that's a good reason to make the UI more powerful and allow more aspects of the Stokes drift to be set). Note, improving the accuracy with which Stokes drift + derivatives are computed is good, but if the Stokes drift is only marginally resolved, then one might also want to worry about the accuracy of the dynamics themselves. Increasing the accuracy of the Stokes drift computation may only go so far if the equations of motion themselves are underresolved. Could be an interesting topic for research though. |
This experimental PR tweaks the pressure correction algorithm so that Lagrangian-mean velocities can be divergent. This might be convenient in practice, since otherwise users are tasked with correctly extracting the solenoidal part of the Stokes drift (eg Vanneste and Young 2022).
The simple change to the algorithm is basically to omit the dt_uS term on the RHS, and instead add the uS contribution manually. The pressure correction is performed on uE. For this to work users have to provide uS rather than dt_uS.
We could merge this, but if we do I want to change the user interface a bit. Basically I think users should either provide dt_uS or uS but not both. That allows the user to select the "mode" (divergnece-free uL, or divergence-free uE).
The new algorithm is illustrated by the following script which disproves a claim in McIntyre (1981) about the ultimate fate of oceanic momentum beneath forced surface waves (McIntyre claimed that the momentum propagates away in shallow water waves, but when the ocean is deep compared to the scale of the packet, the momentum actually stays put at the forcing site).
surface_wave_induced_flow.mp4