Example 5: Rayleigh-Taylor Instability

missing

Rayleigh-Taylor is a very nice qualitative test where heavier fluid rest above a light fluid in a uniform gravitational field. This balance is obviously unstable and the fluids will try to minimize their potential by replacing each other. The transitional state often looks like a mushroom. You can get this in real life when you mix eg. coffee with milk. Some people believe this stuff is important and they made a page on wikipedia for it.

module rayleightaylor

include("../src/LagrangianVoronoi.jl")
using .LagrangianVoronoi

const rho_d = 1.0 # density of lower fluid
const rho_u = 1.8 # density of upper fluid
const Re = 420.0 # Reynold number
const Fr = 1.0 # Froude number
const c = 20.0 # speed of sound
const g = 1/(Fr^2) # gravitational acceleration
const gamma = 1.4

const xlims = (0.0, 1.0)
const ylims = (0.0, 2.0)

const N = 100 #resolution
const dr = 1.0/N
const h = 2*dr

const v_char = 1.0
const l_char = 1.0
const dt = 0.1*dr/v_char
const t_end =  5.0
const nframes = 400

const export_path = "results/rayleightaylor"

Let us define some phase markers for upper and lower fluid. The phase markers must be non-negative integers.

const UP = 0
const DOWN = 1

Accelerate the instability with a good initial condition, where upper and lower fluid are divided by a sinusoid.

function dividing_curve(x::Float64)::Float64
    return 1.0 - 0.15*sin(2*pi*x[1])
end

function ic!(p::VoronoiPolygon)
    dy = dividing_curve(p.x[1])
    p.phase = (p.x[2] > dy ? 0 : 1)
    p.rho = (p.phase == UP ? rho_u : rho_d)
    p.mass = p.rho*area(p)
    p.mu = p.rho/Re
    p.P = rho_d*c^2/gamma
    p.P -= max(p.x[2], dy)*rho_d*g
    p.P -= min(0.0, p.x[2]-dy)*rho_u*g
    p.e = p.P/(p.rho*(gamma - 1.0)) + g*p.x[2]
end

This time we need two different implicit solvers. The psolver is the good old pressure solver and projects velocity to a constraint space with zero divergence (or something similar in the compressible regime). The new msolver projects the repair velocity to a constraint space where it does not mess up the fluid phases. It is not so important, but had I not implemented it, those mathematical puritans would kick me from a Cantor staircase and stab me with a Weierstrass function.

mutable struct Simulation <: SimulationWorkspace
    grid::GridNS
    psolver::PressureSolver{PolygonNS}
    msolver::MultiphaseSolver{PolygonNS}
    E::Float64
    Simulation() = begin
        domain = Rectangle(xlims = xlims, ylims = ylims)
        grid = GridNS(domain, dr)
        populate_lloyd!(grid, ic! = ic!)
        return new(grid, PressureSolver(grid), MultiphaseSolver(grid), 0.0)
    end
end

function step!(sim::Simulation, t::Float64)
    move!(sim.grid, dt)
    gravity_step!(sim.grid, -g*VECY, dt)
    ideal_eos!(sim.grid)
    find_pressure!(sim.psolver, dt)
    pressure_step!(sim.grid, dt)
    find_D!(sim.grid)
    viscous_step!(sim.grid, dt)
    find_dv!(sim.grid, dt)
    multiphase_projection!(sim.msolver) # apply the multiphase solver
    relaxation_step!(sim.grid, dt)
    return
end

function postproc!(sim::Simulation, t::Float64)
    sim.E = 0.0
    for p in sim.grid.polygons
        sim.E += p.mass*p.e
    end
    percent = round(100*t/t_end, digits = 5)
    println("t = $t ($(percent)%)")
    println("energy = $(sim.E)")
    println()
end

function main()
    sim = Simulation()
    run!(sim, dt, t_end, step!,
        path = export_path,
        vtp_vars = (:rho, :P, :v, :phase), save_csv = false,
        postproc! = postproc!,
        nframes = nframes
    )
    return
end

if abspath(PROGRAM_FILE) == @__FILE__
    main()
end

end

This page was generated using Literate.jl.