Skip to content

Commit

Permalink
Merge pull request #285 from FourierFlows/ncc/aliased_fraction-part-o…
Browse files Browse the repository at this point in the history
…f-grid

Enhance user experience with aliasing + (fix bug in `getaliasedwaveumbers`)
  • Loading branch information
navidcy authored Jun 4, 2021
2 parents a4bcb46 + 2939929 commit 7a963c1
Show file tree
Hide file tree
Showing 11 changed files with 415 additions and 182 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ authors = ["Gregory L. Wagner <wagner.greg@gmail.com>", "Navid C. Constantinou <
description = "Tools for building fast, hackable, pseudospectral partial differential equation solvers on periodic domains."
documentation = "https://fourierflows.github.io/FourierFlowsDocumentation/stable/"
repository = "https://github.com/FourierFlows/FourierFlows.jl"
version = "0.6.19"
version = "0.7.0"

[deps]
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
Expand Down
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pages = [
"Installation Instructions" => "installation_instructions.md",
"Code Basics" => "basics.md",
"Grids" => "grids.md",
"Aliasing" => "aliasing.md",
"Problem" => "problem.md",
"GPU" => "gpu.md",
"Examples" => [
Expand Down
77 changes: 77 additions & 0 deletions docs/src/aliasing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Aliasing


```@setup 1
using FourierFlows
using Plots
Plots.scalefontsizes(1.25)
Plots.default(lw=3)
```

In pseudospectral methods, often aliasing errors come into play. These errors originate from
the discrete version of the grid. A grid discretized with ``n_x`` points can only resolve a
total of ``n_x`` wavenumbers in Fourier space.

On a grid with a total of ``n_x`` wavenumbers, both harmonics ``e^{2\pi i k x / L_x}`` and
``e^{2\pi i (k+n_x) x / L_x}``, with ``k`` an integer, are indistinguishable when evaluated
on the discrete grid-points of this grid. When we compute nonlinear terms in physical space,
we may end up with terms that project on higher wavenumbers, beyond those that our grid can
represent. In that case, those wavenumbers will be erroneously projected onto some lower
wavenumber mode that fits our domain.

Take, for example, functions ``\cos(4x)`` and ``\cos(6x)`` and let's see how they are represented
on a grid ``x \in [-π, π)`` with ``n_x = 10``.

```@example 1
nx, Lx = 10, 2π
grid = OneDGrid(nx, Lx)
f1(x) = cos(4x)
f2(x) = cos(6x)
p = plot(grid.x, f1.(grid.x), lw=0, marker=:circle, c=:red, ms=8, ylims=(-1.6, 1.6), label="cos(4x)")
plot!(p, f1, lw=3, alpha=0.2, c=:red, xlims=(-Lx/2, Lx/2), label="")
plot!(p, grid.x, f2.(grid.x), lw=0, marker=:star5, ms=8.5, color=:blue, alpha=0.8, label="cos(6x)")
plot!(p, f2, lw=3, alpha=0.2, c=:blue, xlims=(-Lx/2, Lx/2), label="")
plot(p, xlabel="x", xlims=(-3.3, 3.3))
savefig("assets/plot4.svg"); nothing # hide
```

![](assets/plot4.svg)

The take home message is that on this grid we cannot distinguish harmonics of wavenumbers 4 and 6
and attempting to represent harmonics with wavenumber 6 on this grid will lead to aliasing errors.
For example, say that we are solving an equation on this grid and at some point we compute the product
``\cos(2x) \cos(4x)``. The result is ``\frac1{2} \cos(2x) + \frac1{2} \cos(6x)``, but on this
grid ``\cos(6x)`` is indistinguishable from ``\cos(4x)`` and, therefore, we get an answer
which is the sum of ``\frac1{2} \cos(2x) + \frac1{2} \cos(4x)``!

There are two ways to avoid aliasing errors we either *(i)* need to discard some of the wavenumber
components in Fourier space before we tranform to physical space, or *(ii)* pad our Fourier
represresentation with more wavenumbers that will have zero power. In FourierFlows.jl the former
is implemented

!!! info "De-aliasing scheme"
FourierFlows.jl curently implement dealiasing by zeroing out the top-`aliased_fraction`
wavenumber components on a `grid`.

How many wavenumber components we need to discard depends on the order of the nonlinearity. For
quadradic nonlinearities, one would intuitively say that we need to discard the top-1/2 of the
wavenumber components. However, Orszag (1972) pointed out that simply only discarding the
top-1/3 of wavenumber components is enough. Actally, with Orszag's so-called 2/3-rule for dealiasing,
still some aliasing errors occur, but only into wavenumbers that will be zero-ed out next time
we dealias.

When constructing a `grid` we can specify the `aliased_fraction` parameter. By default, this is
set to ``1/3``, appropriate for quadratic nonlinearities. Then `dealias!(fh, grid)` will zero-out
the top-`aliased_fraction` wavenumber components of `fh`.

If we construct a grid with `aliased_fraction=0`, e.g.,

```@example 1
grid_nodealias = OneDGrid(nx, Lx; aliased_fraction=0)
```

then `dealias!(fh, grid_nodealias)` will have _no effect_ whatsoever on `fh`.
4 changes: 3 additions & 1 deletion docs/src/gpu.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ OneDimensionalGrid
├────────── size Lx: 2.0
├──── resolution nx: 16
├── grid spacing dx: 0.125
└─────────── domain: x [-1.0, 0.875]
├─────────── domain: x [-1.0, 0.875]
└─ aliased fraction: 0.3333333333333333

```

gives out a grid whose arrays are `CuArrays`. (Calling `OneDGrid(n, L)` defaults to CPU, i.e.,
Expand Down
5 changes: 3 additions & 2 deletions docs/src/grids.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ OneDimensionalGrid
├────────── size Lx: 6.283185307179586
├──── resolution nx: 64
├── grid spacing dx: 0.09817477042468103
└─────────── domain: x ∈ [-3.141592653589793, 3.0434178831651124]
```
├─────────── domain: x ∈ [-3.141592653589793, 3.0434178831651124]
└─ aliased fraction: 0.3333333333333333
```

The grid domain is, by default, constructed symmetrically around ``x = 0``, but this
can be altered using the `x0` keyword argument of `OneDGrid` constructor. The grid
Expand Down
4 changes: 2 additions & 2 deletions docs/src/problem.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,10 @@ plot!(x -> cos(π * x) * exp(-prob.params.α * 2), -1, 1, label = "analytical")
plot!(x -> cos(π * x), -1, 1, linestyle=:dash, color=:gray, label = "initial condition")
savefig("assets/plot4.svg"); nothing # hide
savefig("assets/plot5.svg"); nothing # hide
```

![](assets/plot4.svg)
![](assets/plot5.svg)

A good practice is to encompass all functions and type definitions related with a PDE under
a single module, e.g.,
Expand Down
2 changes: 1 addition & 1 deletion examples/OneDShallowWaterGeostrophicAdjustment.jl
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function calcN!(N, sol, t, clock, vars, params, grid)
@. N[:, 2] = - params.f * vars.uh # - f u
@. N[:, 3] = - im * grid.kr * params.H * vars.uh # - H ∂u/∂x

dealias!(N, grid, grid.kralias)
dealias!(N, grid)

return nothing
end
Expand Down
2 changes: 1 addition & 1 deletion src/FourierFlows.jl
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ using Base: fieldnames
using FFTW: fftfreq, rfftfreq

"Abstract supertype for grids."
abstract type AbstractGrid{T, A} end
abstract type AbstractGrid{T, A, Alias} end

"Abstract supertype for timesteppers."
abstract type AbstractTimeStepper{T} end
Expand Down
Loading

2 comments on commit 7a963c1

@navidcy
Copy link
Member Author

@navidcy navidcy commented on 7a963c1 Jun 4, 2021

Choose a reason for hiding this comment

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

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

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

Registration pull request created: JuliaRegistries/General/38132

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.7.0 -m "<description of version>" 7a963c1c55adc0c3ac7346709b12ba2ef54d1a19
git push origin v0.7.0

Please sign in to comment.