-
Notifications
You must be signed in to change notification settings - Fork 195
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
[WIP] Adds a pertubation advection open boundary matching scheme #3977
base: main
Are you sure you want to change the base?
Conversation
@tomchor, do you think something like this: Oceananigans.jl/validation/open_boundaries/cylinder.jl Lines 18 to 76 in 32cd354
could belong in Oceanostics? |
I have also run the same case with different domain lengths (6m, 12m - shown, 18m and 30m) and they all produce very similar Cd and St |
Sure! Why not? :) |
@inline function _fill_east_halo!(j, k, grid, u, bc::PAOBC, loc::Tuple{Face, Any, Any}, clock, model_fields) | ||
i = grid.Nx + 1 | ||
|
||
Δt = clock.last_stage_Δt | ||
|
||
Δt = ifelse(isinf(Δt), 0, Δt) | ||
|
||
Δx = xspacing(i, j, k, grid, loc...) | ||
|
||
ūⁿ⁺¹ = getbc(bc, j, k, grid, clock, model_fields) | ||
|
||
uᵢⁿ = @inbounds u[i, j, k] | ||
uᵢ₋₁ⁿ⁺¹ = @inbounds u[i - 1, j, k] | ||
|
||
U = max(0, min(1, Δt / Δx * ūⁿ⁺¹)) | ||
|
||
τ = ifelse(ūⁿ⁺¹ >= 0, | ||
bc.classification.matching_scheme.outflow_timescale, | ||
bc.classification.matching_scheme.inflow_timescale) | ||
|
||
|
||
τ̃ = Δt / τ | ||
|
||
uᵢⁿ⁺¹ = (uᵢⁿ + U * uᵢ₋₁ⁿ⁺¹ + ūⁿ⁺¹ * τ̃) / (1 + τ̃ + U) | ||
|
||
@inbounds u[i, j, k] = uᵢⁿ⁺¹#ifelse(active_cell(i, j, k, grid), uᵢⁿ⁺¹, zero(grid)) | ||
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.
I think we could implement everything using getindex()
so that we implement it once (or at max twice; one for left and other for right BC) and can use it in three dimensions.
For example this
uᵢⁿ = @inbounds u[i, j, k]
uᵢ₋₁ⁿ⁺¹ = @inbounds u[i - 1, j, k]
would become
uᵢⁿ = @inbounds getindex(u, boundary_indices...)
uᵢ₋₁ⁿ⁺¹ = @inbounds getindex(u, one_off_boundary_indices...)
This would avoid errors when transcribing to other dimensions (I remember catching a couple for the flat extrapolation matching scheme).
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.
yeah, I was trying to think of a clean way to do this
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.
Attempted this now (but I've still not written out the other directions in case we want to change things first)
0e645c5
to
32cd354
Compare
U = 1 | ||
D = 1. | ||
resolution = D / 40 | ||
```math |
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.
Actually the pressure contribution shouldn't be included here since G^n
doesn't include it right?
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 can't see the line you're referring to
afecfb3
to
e66f3d1
Compare
There's a typo in your top equation right? I think it should be |
What do you mean? What is the consequence of this approximation? |
I was thinking about this more and really to remain valid then in : as I found a typo in the west boundary which might be why the oscillating case wasn't working, rerunning now |
|
Okay, I agree with you. You can also analyze the update formula / backward Euler step in the limit U -> 0. It doesn't look like it needs to be regularized in any way in that case though, it looks ok. |
Is there a reference for this method? If there is, please include it on the methods docstring. If not, it'd be good to include a brief explanation like the one at the top comment in the dosctring. I don't think this radiation method is very well known. |
I started implementing some code to return the wall-normal velocity which can be put in as the U in this scheme, and I'm not exactly sure where to put it. I have it in the boundary conditions module but it would be very helpful to have it after fields and abstract operations. If its in boundary conditions I have to make a struct and write a kernel etc. but otherwise I think it can just be something like: Ū = sum(u * A / sum(A, dims = (2, 3)), dims = (2, 3)) etc. |
I've pushed the wall normal velocity thing in |
\\frac{\\partial \\vec{u}}{\\partial t} + (\\vec{u}\\cdot\\nabla)\\vec{u}=-\\nabla P + \\nabla\\cdot\\vec{\\tau} + \\vec{F},\\newline | ||
\\vec{F}_T=\\int_\\Omega\\vec{F}dV = \\int_\\Omega\\left(\\frac{\\partial \\vec{u}}{\\partial t} + (\\vec{u}\\cdot\\nabla)\\vec{u}+\\nabla P - \\nabla\\cdot\\vec{\\tau}\\right)dV,\\newline | ||
\\vec{F}_T=\\int_\\Omega\\left(\\frac{\\partial \\vec{u}}{\\partial t}\\right)dV + \\oint_{\\partial\\Omega}\\left(\\vec{u}(\\vec{u}\\cdot\\hat{n}) + P\\hat{n} - \\vec{\\tau}\\cdot\\hat{n}\\right)dS,\\newline | ||
\\F_u=\\int_\\Omega\\left(\\frac{\\partial u}{\\partial t}\\right)dV + \\oint_{\\partial\\Omega}\\left(u(\\vec{u}\\cdot\\hat{n}) - \\tau_{xx}\\right)dS + \\int_{\\partial\\Omega}P\\hat{x}\\cdot d\\vec{S},\\newline | ||
F_u=\\int_\\Omega\\left(\\frac{\\partial u}{\\partial t}\\right)dV - \\int_{\\partial\\Omega_1} \\left(u^2 - 2\\nu\\frac{\\partial u}{\\partial x} + P\\right)dS + \\int_{\\partial\\Omega_2}\\left(u^2 - 2\\nu\\frac{\\partial u}{\\partial x}+P\\right)dS - \\int_{\\partial\\Omega_2} uvdS + \\int_{\\partial\\Omega_4} uvdS, | ||
``` | ||
where the bounding box is ``\\Omega`` which is formed from the boundaries ``\\partial\\Omega_{1}``, ``\\partial\\Omega_{2}``, ``\\partial\\Omega_{3}``, and ``\\partial\\Omega_{4}`` | ||
which have outward directed normals ``-\\hat{x}``, ``\\hat{x}``, ``-\\hat{y}``, and ``\\hat{y}`` |
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.
Should we re-write this as unicode? I can't understand at all the equations without rendering the latex code
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 guess so, docs should render latex in docstrings but since this isn't going to ever be rendered by Documenter its probably makes more sense in unicode
f4cba4e
to
be2f2ad
Compare
be2f2ad
to
3257eec
Compare
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.
One comment is that I think the name is a bit ambiguous. There are several open boundary methods that have been developed that (in addition to outflow) include some sort of added perturbation for inflows to allow for faster turbulence development. When I read PerturbationAdvection
I think of those methods. But if I understand the code correctly the "perturbation" here refers only to perturbations in the outflow, no?
Maybe we could name it PerturbationOutflow
to avoid confusion?
The results of simple cases seem more correct doing a forward step + |
I'm also pulling the changes from #3937 in but the diff with main will go away when that PR is merged |
I'm not exactly sure, if there was a point inflowing but the mean flow is out it still gets advected. Also when you add inflow pertubation its not advecting anything right? You could also achieve that by setting e.g. |
I thought the inflow was also advecting stuff into the domain. But it would advect a mostly-laminar flow. In any case, imo it would be nice to change the name to something that would differentiate from methods that add a perturbation to inflow velocities in order to speed up transition to turbulence. Do you have suggestions? |
This PR adds a
PertubationAdvection
open boundary condition which assumes that there is some mean flow (i.e. prescribed in a channel or from a coarser resolution model) which is homogeneous on the boundary but can vary in time.On the boundary, we approximate (for an x-boundary) to:
where$u=u\prime+U$
I have chosen to take an explicit/backwards Euler step:
because then we don't have to store any other information (i.e. if we did a forward step we would need$u\prime(x_{b-1}, t^n)$ ). This results in:
where$\tilde{U}=\min\left(1, U\Delta t / \Delta x\right)$ . I have also added restoring to $U$ (i.e. damping $u\prime\to0$ ) in some timescale $\tau$ which can be different for inflow and outflow to allow the scheme to work when there is inflow, which results in:
where$\tilde{\tau}=\Delta t / \tau$ .
This has the limitation that if we want to extend to have wall tangent mean velocity ($\partial_t u \approx -(\vec{U}\cdot\nabla) u$ ) then we either have to solve the whole boundary at once since every point is going to depend on its boundary neighbours, or we need to take a forward Euler step in which case we need the first interior point at the previous time step.
I think we probably will need to address this for real nesting cases at some point.
I will link a full write-up of how I derived this scheme when it's done. I have also only implemented in the x direction for testing and will do the others once I'm happy with it.
For now, it seems to be working okay (left plot vorticity, right plot x-velocity):
open.mp4
and the drag coefficient is ~1.4 at Re = 100 and I'm running a case at Re=1000 now.
I have also checked the Strouhal number which matches exactly to the expected values (~0.17).
A problem I think this scheme might have is that as the flow changes direction the assumption that the perturbation is small falls apart, which is maybe why it's been a bit unstable so far in an oscillating case.