Skip to content

Note: Output is not generated for this example (to save resources on GitHub).

Rayleigh-Bénard convection (3D)

A hot and a cold plate generate a convection cell in a box.

julia
using CairoMakie
using IncompressibleNavierStokes

Hardware

julia
backend = CPU()

# using CUDA, CUDSS
# backend = CUDABackend()

Precision

julia
T = Float32

Output directory

julia
outdir = joinpath(@__DIR__, "output", "RayleighBenard3D")

Temperature equation

julia
temperature = temperature_equation(;
    Pr = T(0.71),
    Ra = T(1e7),
    Ge = T(1.0),
    dodissipation = true,
    boundary_conditions = (
        (PeriodicBC(), PeriodicBC()),
        (SymmetricBC(), SymmetricBC()),
        (DirichletBC(T(1)), DirichletBC(T(0))),
    ),
    gdir = 3,
    nondim_type = 1,
)

Setup

julia
n = 60
x = (
    LinRange(T(0), T(π), 2n),
    tanh_grid(T(0), T(1), n, T(1.2)),
    tanh_grid(T(0), T(1), n, T(1.2)),
)
setup = Setup(;
    x,
    boundary_conditions = (
        (PeriodicBC(), PeriodicBC()),
        (DirichletBC(), DirichletBC()),
        (DirichletBC(), DirichletBC()),
    ),
    Re = 1 / temperature.α1,
    temperature,
    backend,
);

plotgrid(x[1], x[2])
plotgrid(x[2], x[3])

This will factorize the Laplace matrix

julia
@time psolver = psolver_direct(setup)

Initial conditions

julia
ustart = velocityfield(setup, (dim, x, y, z) -> zero(x); psolver);
tempstart =
    temperaturefield(setup, (x, y, z) -> one(x) / 2 + sin(20 * x) * sinpi(20 * y) / 100);
nothing #hide

Solve equation

julia
state, outputs = solve_unsteady(;
    setup,
    ustart,
    tempstart,
    tlims = (T(0), T(10)),
    method = RKMethods.RK33C2(; T),
    # Δt = T(1e-2),
    psolver,
    processors = (;
        # anim = animator(;
        #     path = "$outdir/RB3D.mp4",
        rtp = realtimeplotter(;
            setup,
            nupdate = 1,
            levels = LinRange(-T(5), T(1), 10),
            fieldname = :eig2field,
            # levels = LinRange{T}(0.01, 0.99, 10),
            # fieldname = :temperature,
        ),
        # vtk = vtk_writer(;
        #     setup,
        #     dir = joinpath(outdir, "RB3D_$n"),
        #     nupdate = 20,
        #     ## fieldnames = (:velocity, :temperature, :eig2field)
        #     fieldnames = (:temperature,),
        # ),
        log = timelogger(; nupdate = 100),
    ),
);

field = IncompressibleNavierStokes.eig2field(state.u, setup)[setup.grid.Ip]
hist(vec(Array(log.(max.(eps(T), .-field)))))

fieldplot(
    # (; u = ustart, temp = tempstart, t = T(0));
    state;
    setup,
    levels = LinRange{T}(0.5, 2, 5),
    # levels = LinRange(-T(5), T(1), 10),
    # fieldname = :eig2field,
    fieldname = :temperature,
)

Copy-pasteable code

Below is the full code for this example stripped of comments and output.

julia
using GLMakie
using IncompressibleNavierStokes

backend = CPU()

# using CUDA, CUDSS
# backend = CUDABackend()

T = Float32

outdir = joinpath(@__DIR__, "output", "RayleighBenard3D")

temperature = temperature_equation(;
    Pr = T(0.71),
    Ra = T(1e7),
    Ge = T(1.0),
    dodissipation = true,
    boundary_conditions = (
        (PeriodicBC(), PeriodicBC()),
        (SymmetricBC(), SymmetricBC()),
        (DirichletBC(T(1)), DirichletBC(T(0))),
    ),
    gdir = 3,
    nondim_type = 1,
)

n = 60
x = (
    LinRange(T(0), T(π), 2n),
    tanh_grid(T(0), T(1), n, T(1.2)),
    tanh_grid(T(0), T(1), n, T(1.2)),
)
setup = Setup(;
    x,
    boundary_conditions = (
        (PeriodicBC(), PeriodicBC()),
        (DirichletBC(), DirichletBC()),
        (DirichletBC(), DirichletBC()),
    ),
    Re = 1 / temperature.α1,
    temperature,
    backend,
);

plotgrid(x[1], x[2])
plotgrid(x[2], x[3])

@time psolver = psolver_direct(setup)

ustart = velocityfield(setup, (dim, x, y, z) -> zero(x); psolver);
tempstart =
    temperaturefield(setup, (x, y, z) -> one(x) / 2 + sin(20 * x) * sinpi(20 * y) / 100);

state, outputs = solve_unsteady(;
    setup,
    ustart,
    tempstart,
    tlims = (T(0), T(10)),
    method = RKMethods.RK33C2(; T),
    # Δt = T(1e-2),
    psolver,
    processors = (;
        # anim = animator(;
        #     path = "$outdir/RB3D.mp4",
        rtp = realtimeplotter(;
            setup,
            nupdate = 1,
            levels = LinRange(-T(5), T(1), 10),
            fieldname = :eig2field,
            # levels = LinRange{T}(0.01, 0.99, 10),
            # fieldname = :temperature,
        ),
        # vtk = vtk_writer(;
        #     setup,
        #     dir = joinpath(outdir, "RB3D_$n"),
        #     nupdate = 20,
        #     ## fieldnames = (:velocity, :temperature, :eig2field)
        #     fieldnames = (:temperature,),
        # ),
        log = timelogger(; nupdate = 100),
    ),
);

field = IncompressibleNavierStokes.eig2field(state.u, setup)[setup.grid.Ip]
hist(vec(Array(log.(max.(eps(T), .-field)))))

fieldplot(
    # (; u = ustart, temp = tempstart, t = T(0));
    state;
    setup,
    levels = LinRange{T}(0.5, 2, 5),
    # levels = LinRange(-T(5), T(1), 10),
    # fieldname = :eig2field,
    fieldname = :temperature,
)

This page was generated using Literate.jl.