Skip to content
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

Implementation of the scale-dependent Lagrangian-averaged dynamic Smagorinsky #3638

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

xkykai
Copy link
Collaborator

@xkykai xkykai commented Jun 24, 2024

Closes #3637

This is an implementation of the scale-dependent Lagrangian-averaged dynamic Smagorinsky model as outlined in section C III. in Bou-Zeid et al. 2005.

@simone-silvestri @tomchor

@@ -225,6 +225,8 @@ end
u̅w̅ = ℑxyzᶜᶜᶜ(i, j, k, grid, ℑxyzᶠᶠᶠ, ℑxyzᶜᶜᶜ, ℑxyzᶠᶠᶠ, uᵢuⱼ, ℑxᶜᵃᵃ, ℑzᵃᵃᶜ, u, w)
v̅w̅ = ℑxyzᶜᶜᶜ(i, j, k, grid, ℑxyzᶠᶠᶠ, ℑxyzᶜᶜᶜ, ℑxyzᶠᶠᶠ, uᵢuⱼ, ℑyᵃᶜᵃ, ℑzᵃᵃᶜ, v, w)

S̅ₘ = ℑxyzᶜᶜᶜ(i, j, k, grid, ℑxyzᶠᶠᶠ, ℑxyzᶜᶜᶜ, ℑxyzᶠᶠᶠ, ϕ⁰⁵, ΣᵢⱼΣᵢⱼᶜᶜᶜ, u, v, w)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Currently the code goes into StackOverflowError, likely due to the way the filter averaging is done as we might have function compositions which are too deep.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Does it work if we use a simpler filter?

Copy link
Collaborator

Choose a reason for hiding this comment

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

we can maybe use a box filter here instead of all this combination of interpolations.
We can add a filter function to the struct

Copy link
Member

Choose a reason for hiding this comment

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

Hmm. But this should not be an overflow error, right? Are we hitting some heuristic?

I would try combining steps to see what happens. For example you could define

ϕ⁰⁵_ΣᵢⱼΣᵢⱼᶜᶜᶜ(i, j, k, grid, u, v, w) = ϕ⁰⁵(i, j, k, grid, ΣᵢⱼΣᵢⱼᶜᶜᶜ, u, v, w)

You could also simply write the whole thing manually. With composition this deep, it might also make this code easier to understand.

Copy link
Member

Choose a reason for hiding this comment

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

Does it work if we use a simpler filter?

What is complicated about this?

@xkykai xkykai added numerics 🧮 So things don't blow up and boil the lobsters alive turbulence closures 🎐 labels Jun 24, 2024
@tomchor
Copy link
Collaborator

tomchor commented Jun 24, 2024

We should "Close #3637" with this one I think

Comment on lines +262 to +267
M₁₁ = 2Δᶠ * (S̅S̅₁₁ - α^2 * β^2 * S̅ₘ * S̅₁₁)
M₂₂ = 2Δᶠ * (S̅S̅₂₂ - α^2 * β^2 * S̅ₘ * S̅₂₂)
M₃₃ = 2Δᶠ * (S̅S̅₃₃ - α^2 * β^2 * S̅ₘ * S̅₃₃)
M₁₂ = 2Δᶠ * (S̅S̅₁₂ - α^2 * β^2 * S̅ₘ * S̅₁₂)
M₁₃ = 2Δᶠ * (S̅S̅₁₃ - α^2 * β^2 * S̅ₘ * S̅₁₃)
M₂₃ = 2Δᶠ * (S̅S̅₂₃ - α^2 * β^2 * S̅ₘ * S̅₂₃)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this be

Suggested change
M₁₁ = 2Δᶠ * (S̅S̅₁₁ - α^2 * β^2 * S̅ₘ * S̅₁₁)
M₂₂ = 2Δᶠ * (S̅S̅₂₂ - α^2 * β^2 * S̅ₘ * S̅₂₂)
M₃₃ = 2Δᶠ * (S̅S̅₃₃ - α^2 * β^2 * S̅ₘ * S̅₃₃)
M₁₂ = 2Δᶠ * (S̅S̅₁₂ - α^2 * β^2 * S̅ₘ * S̅₁₂)
M₁₃ = 2Δᶠ * (S̅S̅₁₃ - α^2 * β^2 * S̅ₘ * S̅₁₃)
M₂₃ = 2Δᶠ * (S̅S̅₂₃ - α^2 * β^2 * S̅ₘ * S̅₂₃)
M₁₁ = 2Δᶠ * (S̅S̅₁₁ - α^2 * β * S̅ₘ * S̅₁₁)
M₂₂ = 2Δᶠ * (S̅S̅₂₂ - α^2 * β * S̅ₘ * S̅₂₂)
M₃₃ = 2Δᶠ * (S̅S̅₃₃ - α^2 * β * S̅ₘ * S̅₃₃)
M₁₂ = 2Δᶠ * (S̅S̅₁₂ - α^2 * β * S̅ₘ * S̅₁₂)
M₁₃ = 2Δᶠ * (S̅S̅₁₃ - α^2 * β * S̅ₘ * S̅₁₃)
M₂₃ = 2Δᶠ * (S̅S̅₂₃ - α^2 * β * S̅ₘ * S̅₂₃)

?

Copy link
Member

Choose a reason for hiding this comment

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

Can you paste in the reference that shows this?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Taking a second look at things I now think there may be more typos than this one. So I suggest @xkykai and @simone-silvestri double-check this, but if I understand correctly, what's called 𝒥ᴿᴺ in this PR is called $\mathcal J^{QN}$in Bou-Zeid et al. (2005), and here's its advection equation:

image

so using the language of this PR the forcing here should be

1 / T4Δ * (QᵢⱼNᵢⱼ - 𝒥ᴿᴺ)

instead of what's written below: 1 / TΔ * (LᵢⱼMᵢⱼ - 𝒥ᴿᴺ).

And the functions $Q_{ij}$ and $N_{ij}$ are:

image

Similar comments are valid for the function below (𝒥ᴺᴺ_forcing_function()).

Copy link
Collaborator

Choose a reason for hiding this comment

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

For the record, my original comment had to do with $M_{ij}$ being implemented as M₁₁ = 2Δᶠ * (S̅S̅₁₁ - α^2 * β^2 * S̅ₘ * S̅₁₁) when it should be

image

but now (per my previous comment) I realize that $M_{ij}$ isn't supposed to be in this forcing function at all.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The difference between Q and L (and M and N) is the filter size. The stresses for the 𝒥ᴿᴺ forcings are averaged twice as much as the 𝒥ᴸᴹ forcings (if you look at how the averages are calculated). However, I would say that to push this PR forward we need to:

  • define an averaging operators (to be held in the closure struct) for the M - L fluxes and for the R - N fluxes
  • remove all this combination of interpolations in favor of those averaging operators

Copy link
Collaborator

Choose a reason for hiding this comment

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

The difference between Q and L (and M and N) is the filter size.

Agreed. The $N$ and $M$ nomenclature difference makes it clearer though. That said, the combination $\alpha^2 \beta^2$ shouldn't appear anywhere, right? It's either $\alpha^4 \beta^2$ or $\alpha^2 \beta$ (unless you hard-coded some sutff I guess)

Copy link
Member

Choose a reason for hiding this comment

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

What do the tilde, hat, and bar mean?

Copy link
Collaborator

Choose a reason for hiding this comment

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

  • Tilde: LES-filtered velocity. In our case it's simply the velocities that come out of model.velocities
  • Bar: First test filter
  • Hat: Second test filter (at a larger spatial scale than the first)

Comment on lines +309 to +314
M₁₁ = 2Δᶠ * (S̅S̅₁₁ - α^2 * β^2 * S̅ₘ * S̅₁₁)
M₂₂ = 2Δᶠ * (S̅S̅₂₂ - α^2 * β^2 * S̅ₘ * S̅₂₂)
M₃₃ = 2Δᶠ * (S̅S̅₃₃ - α^2 * β^2 * S̅ₘ * S̅₃₃)
M₁₂ = 2Δᶠ * (S̅S̅₁₂ - α^2 * β^2 * S̅ₘ * S̅₁₂)
M₁₃ = 2Δᶠ * (S̅S̅₁₃ - α^2 * β^2 * S̅ₘ * S̅₁₃)
M₂₃ = 2Δᶠ * (S̅S̅₂₃ - α^2 * β^2 * S̅ₘ * S̅₂₃)
Copy link
Collaborator

@tomchor tomchor Jun 24, 2024

Choose a reason for hiding this comment

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

Same comment here

Suggested change
M₁₁ = 2Δᶠ * (S̅S̅₁₁ - α^2 * β^2 * S̅ₘ * S̅₁₁)
M₂₂ = 2Δᶠ * (S̅S̅₂₂ - α^2 * β^2 * S̅ₘ * S̅₂₂)
M₃₃ = 2Δᶠ * (S̅S̅₃₃ - α^2 * β^2 * S̅ₘ * S̅₃₃)
M₁₂ = 2Δᶠ * (S̅S̅₁₂ - α^2 * β^2 * S̅ₘ * S̅₁₂)
M₁₃ = 2Δᶠ * (S̅S̅₁₃ - α^2 * β^2 * S̅ₘ * S̅₁₃)
M₂₃ = 2Δᶠ * (S̅S̅₂₃ - α^2 * β^2 * S̅ₘ * S̅₂₃)
M₁₁ = 2Δᶠ * (S̅S̅₁₁ - α^2 * β * S̅ₘ * S̅₁₁)
M₂₂ = 2Δᶠ * (S̅S̅₂₂ - α^2 * β * S̅ₘ * S̅₂₂)
M₃₃ = 2Δᶠ * (S̅S̅₃₃ - α^2 * β * S̅ₘ * S̅₃₃)
M₁₂ = 2Δᶠ * (S̅S̅₁₂ - α^2 * β * S̅ₘ * S̅₁₂)
M₁₃ = 2Δᶠ * (S̅S̅₁₃ - α^2 * β * S̅ₘ * S̅₁₃)
M₂₃ = 2Δᶠ * (S̅S̅₂₃ - α^2 * β * S̅ₘ * S̅₂₃)

@tomchor
Copy link
Collaborator

tomchor commented Jun 24, 2024

I'm curious as to why you picked α=4. It makes for a pretty big stencil and α=2 works pretty well already. Does it have to do with the filtering being two consecutive interpolations?

@simone-silvestri
Copy link
Collaborator

This is also not super clean because the forcing functions for the additional tracers are added manually to the model.
It would be better to have a way to include them directly when prescribing this closure.

@xkykai
Copy link
Collaborator Author

xkykai commented Jun 24, 2024

I believe what we are doing here is using two filter scales α=2 and α=4 to compute β, which is ratio of coefficients at different filter scales Δ, αΔ, and α²Δ, assuming that β is scale-invariant.

@tomchor
Copy link
Collaborator

tomchor commented Jun 24, 2024

I believe what we are doing here is using two filter scales α=2 and α=2 to compute β, which is ratio of coefficients at different filter scales Δ, αΔ, and α²Δ, assuming that β is scale-invariant.

Hmm, then I'm confused. When you assume β to be scale-invariant you only need two filters: the grid (Δ) and a test filter (αΔ). afaik the second test filter is only needed when assuming that β can vary between scales.

@xkykai
Copy link
Collaborator Author

xkykai commented Jun 24, 2024

afaik the second test filter is only needed when assuming that β can vary between scales.

I think you're correct here! Sorry for the confusion here, but I suppose by scale-invariance I mean β has a power law dependence on the scale size. And since we were trying to implement the scale-dependent version, β would vary across different scales? Hence we need the α=4 filter as well. Am I understanding Equation (26) in Bou-Zeid et al. 2005 correctly here?

@tomchor
Copy link
Collaborator

tomchor commented Jun 24, 2024

afaik the second test filter is only needed when assuming that β can vary between scales.

I think you're correct here! Sorry for the confusion here, but I suppose by scale-invariance I mean β has a power law dependence on the scale size. And since we were trying to implement the scale-dependent version, β would vary across different scales? Hence we need the α=4 filter as well. Am I understanding Equation (26) in Bou-Zeid et al. 2005 correctly here?

Ah, I see, I was under the impression you were trying to implement the scale-invariant version, but it does make sense to if you're implementing the scale-dependent version.

Pr=0.7
Ri = 0.5
Ni=10
end_time=1000
Copy link
Member

Choose a reason for hiding this comment

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

What is going on here? Isn't there already a script for invoking the utilities in this script?

@@ -113,7 +125,7 @@ function simulate_stratified_couette_flow(; Nxy, Nz, arch=GPU(), h=1, U_wall=1,
##### Impose boundary conditions
#####

grid = RectilinearGrid(arch, size = (Nxy, Nxy, Nz), extent = (4π*h, 2π*h, 2h))
grid = RectilinearGrid(arch, size = (Nxy, Nxy, Nz), extent = (4π*h, 2π*h, 2h), halo = (6, 6, 6))
Copy link
Member

@glwagner glwagner Jun 25, 2024

Choose a reason for hiding this comment

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

Suggested change
grid = RectilinearGrid(arch, size = (Nxy, Nxy, Nz), extent = (4π*h, 2π*h, 2h), halo = (6, 6, 6))
grid = RectilinearGrid(arch; size = (Nxy, Nxy, Nz), extent = (4π*h, 2π*h, 2h), halo)

make this cleaner by adding halo as an argument to simulate_stratified_couette_flow.

Also, it doesn't look like the closure is an argument to simulate_stratified_couette_flow. You'll need that too. (You can also infer the halo size.)

Just as a general tip, I think you will save time if you generalize these functions first. Now, you are in the position of having to 1) walk back the changes you made and then 2) implement an interface that allows different closures. This is actually more work then if you had simply done (2) to begin with.

@glwagner
Copy link
Member

glwagner commented Jul 7, 2024

This is also not super clean because the forcing functions for the additional tracers are added manually to the model. It would be better to have a way to include them directly when prescribing this closure.

I suggest implementing the tracer-specific forcing in a similar manner that we do for CATKE and k-epsilon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
numerics 🧮 So things don't blow up and boil the lobsters alive turbulence closures 🎐
Projects
None yet
Development

Successfully merging this pull request may close these issues.

More / more flexible Smagorinsky models
4 participants