Example 8: Taylor-Green Vortex

In the field of mathematical modeling, benchmarks can be divided into two categories: those which are very cool but completely useless and those which are useful but extremely boring. Taylor-Green vortex belong to the second category. There is nothing interesting here: the fluid has only one phase and the velocity field is smooth and steady periodic vortex lattice. However, it has an analytic solution and we can use it to assess the convergence rate. So far, we only have linear rate but maybe in distant future, somebody implements a second order operators for Lagrangian Voronoi cells.

module taylorgreen
include("../src/LagrangianVoronoi.jl")
using .LagrangianVoronoi, WriteVTK, LinearAlgebra
using DataFrames, CSV, Plots, Measures


const rho0 = 1.0
const xlims = (0.0, 1.0)
const ylims = (0.0, 1.0)
const t_end = 0.2
const Res = [400, 1000, Inf]
const Ns = [32, 48, 72, 108, 162]
const c0 = 1000.0
const gamma = 1.4
const P0 = rho0*c0^2/gamma

const l_char = 1.0
const v_char = 1.0

const export_path = "results/taylorgreen"

function v_max(Re::Float64, t::Float64)::Float64
    return exp(-8.0*pi^2*t/Re)
end

function ic!(p::VoronoiPolygon, Re::Float64)
    p.v = v_exact(p.x, Re, 0.0)
    p.rho = rho0
    p.mass = p.rho*area(p)
    p.P = P_exact(p.x, Re, 0.0)
    p.e = 0.5*norm_squared(p.v) + p.P/(p.rho*(gamma - 1.0))
    p.mu = 1.0/Re
end

function v_exact(x::RealVector, Re::Float64, t::Float64)::RealVector
    u0 =  cos(2pi*x[1])*sin(2pi*x[2])
    v0 = -sin(2pi*x[1])*cos(2pi*x[2])
    return v_max(Re, t)*(u0*VECX + v0*VECY)
end

function P_exact(x::RealVector, Re::Float64, t::Float64)::Float64
    return 0.5*(v_max(Re, t)^2)*(sin(2pi*x[1])^2 + sin(2pi*x[2])^2 - 1.0)
end

mutable struct Simulation <: SimulationWorkspace
    dr::Float64
    dt::Float64
    Re::Float64
    grid::GridNS
    solver::PressureSolver{PolygonNS}
    v_err::Float64
    P_err::Float64
    E_err::Float64
    div::Float64
    first_it::Bool
    E0::Float64
    Simulation(N::Int, Re::Number) = begin
        Re = Float64(Re)
        dr = 1.0/N
        dt = 0.1*min(dr, dr^2*Re)
        domain = Rectangle(xlims = xlims, ylims = ylims)
        grid = GridNS(domain, dr, xperiodic = true, yperiodic = true)
        _ic! = (p -> ic!(p, Re))
        populate_hex!(grid, ic! = _ic!)
        solver = PressureSolver(grid)
        return new(dr, dt, Re, grid, solver, 0.0, 0.0, 0.0, 0.0, true, 0.0)
    end
end

function step!(sim::Simulation, t::Float64)
    move!(sim.grid, sim.dt)
    stiffened_eos!(sim.grid, gamma, P0)
    find_pressure!(sim.solver, sim.dt)
    pressure_step!(sim.grid, sim.dt)
    find_D!(sim.grid)
    viscous_step!(sim.grid, sim.dt; artificial_viscosity = false)
    find_dv!(sim.grid, sim.dt)
    relaxation_step!(sim.grid, sim.dt)
    return
end

function postproc!(sim::Simulation, t::Float64)
    @show t
    grid = sim.grid
    sim.P_err = 0.0
    sim.v_err = 0.0
    sim.E_err = 0.0
    sim.div = 0.0
    p_avg = 0.0
    for p in grid.polygons
        p_avg += area(p)*p.P
    end
    for p in grid.polygons
        sim.E_err += p.mass*p.e
        sim.v_err += area(p)*norm_squared(p.v - v_exact(p.x, sim.Re, t))
        sim.P_err += area(p)*(p.P - p_avg - P_exact(p.x, sim.Re, t))^2
        sim.div += area(p)*(dot(p.D, MAT1)^2)
    end
    if sim.first_it
        sim.E0 = sim.E_err
    end
    sim.E_err -= sim.E0
    sim.P_err = sqrt(sim.P_err)
    sim.v_err = sqrt(sim.v_err)
    sim.div = sqrt(sim.div)
    @show sim.v_err
    @show sim.P_err
    @show sim.E_err
    println()
    sim.first_it = false
    return
end

function simple_test(Re::Number, N::Int)
    sim = Simulation(N, Re)
    run!(sim, sim.dt, t_end, step!;
        postproc! = postproc!,
        nframes = 100,
        path = joinpath(export_path, "N$N"),
        save_csv = false,
        save_points = false,
        save_grid = true,
        vtp_vars = (:P, :v, :rho, :quality, :dv)
    )
end

function get_convergence(Re::Number)
    @show Re
    println("***")
    path = joinpath(export_path, "$(Re)")
    if !ispath(path)
        mkpath(path)
    end
    pvd = paraview_collection(joinpath(path, "cells.pvd"))
    E_errs = Float64[]
    v_errs = Float64[]
    P_errs = Float64[]
    divs = Float64[]
    for N in Ns
        @show N
        sim = Simulation(N, Re)
        run!(sim, sim.dt, t_end, step!;
            postproc! = postproc!,
            nframes = 5,
            path = path,
            save_csv = false,
            save_points = false,
            save_grid = false
        )
        push!(E_errs, abs(sim.E_err))
        push!(v_errs, sim.v_err)
        push!(P_errs, sim.P_err)
        push!(divs, sim.div)
        pvd[N] = export_grid(sim.grid, joinpath(path, "frame$(N).vtp"), :v, :P)
    end
    vtk_save(pvd)
    csv = DataFrame(Ns = Ns, E_errs = E_errs, v_errs = v_errs, P_errs = P_errs, divs = divs)
	CSV.write(joinpath(path, "convergence.csv"), csv)
    for var in (:E_errs, :v_errs, :P_errs, :divs)
        println(var)
        b = linear_regression(Ns, getproperty(csv, var))
        println("noc = $(b[1])")
    end
    println()
    return
end

function linear_regression(x, y)
    N = length(x)
    logx = log10.(x)
    logy = log10.(y)
    A = [logx ones(N)]
    b = A\logy
    return b
end

function main()
    for Re in Res
        get_convergence(Re)
    end
    makeplots()
    return
end

function makeplots()
    rainbow = cgrad(:darkrainbow, length(Res), categorical = true)
    shapes = [:circ, :hex, :square, :star4, :star5, :utriangle, :dtriangle, :pentagon, :rtriangle, :ltriangle]
    for var in (:v_errs, :P_errs, :E_errs, :divs)
        myfont = font(12)
        plt = plot(
            axis_ratio = 1,
            xlabel = "log resolution", ylabel = "log error",
            legend = :bottomleft, #:outerright,
            xtickfont=myfont,
            ytickfont=myfont,
            guidefont=myfont,
            legendfont=myfont,
        )
        i = 1
        ymin = +Inf
        ymax = -Inf
        xmax = -Inf
        for Re in Res
            label = "$(Re)"
            path = joinpath(export_path, label, "convergence.csv")
            csv = CSV.read(path, DataFrame)
            y = getproperty(csv, var)
            x = csv.Ns
            plot!(plt,
                log10.(x), log10.(y), linestyle = :dot,
                markershape = shapes[i],
                label = Re == Inf ? "Re = Inf" : "Re = $(Int(Re))",
                color = rainbow[i],
            )
            xmax = max(xmax, log10(maximum(x)))
            ymax = max(ymax, log10(maximum(y)))
            ymin = min(ymin, log10(minimum(y)))
            i += 1
        end
        trix = xmax + 0.5
        triy = ymax - 0.1
        sidelen = 0.2*(ymax-ymin)
        draw_triangle!(plt, trix, triy, 1, sidelen)
        draw_triangle!(plt, trix, triy, 2, sidelen)
        savefig(plt, joinpath(export_path, "$(var).pdf"))
    end
    return
end

function draw_triangle!(plt, x, y, order = 1, sidelen = 1.0)
    a = sidelen
    shape = [(x-a,y), (x,y), (x, y-a*order), (x-a,y)]
    plot!(plt, shape, linecolor = :black, linestyle = :dash, label = :none)
end

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

end

This page was generated using Literate.jl.