begin
    import Pkg as _Pkg
    haskey(ENV, "PLUTO_PROJECT") && _Pkg.activate(ENV["PLUTO_PROJECT"])
    using Test
    using Revise
    using Printf
    using VoronoiFVM
    using OrdinaryDiffEqBDF
    using OrdinaryDiffEqRosenbrock
    using OrdinaryDiffEqSDIRK
    using LinearAlgebra
    using PlutoUI
    using DataStructures
    using GridVisualize,CairoMakie
end

Solve the nonlinear diffusion equation

$$\partial_t u -\Delta u^m = 0$$

in \(\Omega=(-1,1)\) with homogeneous Neumann boundary conditons using the implicit Euler method.

This equation is also called "porous medium equation". The Barenblatt solution

$$b(x,t)=\max\left(0,t^{-\alpha}\left(1-\frac{\alpha(m-1)r^2}{2dmt^{\frac{2\alpha}{d}}}\right)^{\frac{1}{m-1}}\right)$$

is an exact solution of this problem which for m>1 has a finite support. We initialize this problem with the exact solution for \(t=t_0=0.001\).

(see Barenblatt, G. I. "On nonsteady motions of gas and fluid in porous medium." Appl. Math. and Mech.(PMM) 16.1 (1952): 67-78.)

Here, we compare the implicit Euler approach in VoronoiFVM with the ODE solvers in DifferentialEquations.jl and demonstrate the possibility to use VoronoiFVM to define differential operators compatible with its ODEFunction interface.

function barenblatt(x,t,m)
    tx=t^(-1.0/(m+1.0))
    xx=x*tx
    xx=xx*xx
    xx=1- xx*(m-1)/(2.0*m*(m+1));
    if xx<0.0
        xx=0.0
    end
    return tx*xx^(1.0/(m-1.0))
end
barenblatt (generic function with 1 method)
function create_porous_medium_problem(n,m)
    h=1.0/convert(Float64,n/2)
    X=collect(-1:h:1)
    grid=VoronoiFVM.Grid(X)

    function flux!(f,u,edge,data)
        f[1]=u[1,1]^m-u[1,2]^m
    end

    storage!(f,u,node,data)= f[1]=u[1]

    sys=VoronoiFVM.System(grid,flux=flux!,storage=storage!, species=1)
    sys,X
end
create_porous_medium_problem (generic function with 1 method)
begin
function run_vfvm(;n=20,m=2,t0=0.001, tend=0.01,tstep=1.0e-6)
    sys,X=create_porous_medium_problem(n,m)
    inival=unknowns(sys)
    inival[1,:].=map(x->barenblatt(x,t0,m),X)
    sol=VoronoiFVM.solve(sys;inival,times=(t0,tend),Δt=tstep,Δu_opt=0.01,Δt_min=tstep,store_all=true,log=true, reltol=1.0e-3)
    err=norm(sol[1,:,end]-map(x->barenblatt(x,tend,m),X))
    sol,sys,err
end
run_vfvm(m=2,n=10) # "Precompile"
end;
begin
    function run_diffeq(;n=20,m=2, t0=0.001,tend=0.01,solver=nothing)
        sys,X=create_porous_medium_problem(n,m)
        inival=unknowns(sys)
        inival[1,:].=map(x->barenblatt(x,t0,m),X)
        state=VoronoiFVM.SystemState(sys)
        problem = ODEProblem(state,inival,(t0,tend))
        odesol = solve(problem,solver)
        sol=reshape(odesol,sys; state)
        err=norm(sol[1,:,end]-map(x->barenblatt(x,tend,m),X))
        sol, sys,err
    end
    for method in diffeqmethods
        run_diffeq(m=2,n=10,solver=method.second()) # "Precompile"
    end
end;
OrderedDict{String, UnionAll} with 4 entries:
  "Rosenbrock23 (Rosenbrock)"    => Rosenbrock23
  "QNDF2 (Like matlab's ode15s)" => QNDF2
  "FBDF"                         => FBDF
  "Implicit Euler"               => ImplicitEuler
t1=@elapsed sol1,sys1,err1=run_vfvm(m=m,n=n);history_summary(sol1)
(seconds = 2.03, tasm = 1.67, tlinsolve = 0.338, steps = 832, iters = 1662, maxabsnorm = 2.65e-6, maxrelnorm = 0.000263, maxroundoff = 2.46e-16, iters_per_step = 2.0, facts_per_step = 0.0, liniters_per_step = 0.0)

method:

m=2; n=50;
t2=@elapsed sol2,sys2,err2=run_diffeq(m=m,n=n,solver=diffeqmethods[method]());history_summary(sol2)
(nd = 165, njac = 82, nf = 248)

Left: VoronoiFVM implicit Euler: 2053 ms e=5.17e-02

Right: Rosenbrock23 (Rosenbrock): 182 ms, e=4.62e-02

@test err2<err1
Test Passed

Built with Julia 1.11.1 and