trixi-framework / Trixi.jl

Trixi.jl: Adaptive high-order numerical simulations of conservation laws in Julia
https://trixi-framework.github.io/Trixi.jl
MIT License
535 stars 109 forks source link

Support multiple dimensions #125

Closed ranocha closed 4 years ago

ranocha commented 4 years ago

We can track ideas/suggestions to extend Trixi to multiple dimensions (1D, 2D, and 3D) here. Here is a short summary of our meeting on 2020-08-21.

ranocha commented 4 years ago

Some inspiration for the first task:

julia> abstract type AbstractEquation{NDIMS, V} end

julia> struct AbstractCompressibleEuler{NDIMS, V, T} <: AbstractEquation{NDIMS, V}
           gamma::T
       end

julia> function AbstractCompressibleEuler{NDIMS}(gamma::T) where {NDIMS, T}
           AbstractCompressibleEuler{NDIMS, NDIMS+2, T}(gamma)
       end

julia> AbstractCompressibleEuler{2}(1.4)
AbstractCompressibleEuler{2,4,Float64}(1.4)

julia> @code_warntype AbstractCompressibleEuler{2}(1.4)
Variables
  #self#::Type{AbstractCompressibleEuler{2,V,T} where T where V}
  gamma::Float64

Body::AbstractCompressibleEuler{2,4,Float64}
1 ─ %1 = $(Expr(:static_parameter, 1))::Core.Compiler.Const(2, false)
│   %2 = ($(Expr(:static_parameter, 1)) + 2)::Core.Compiler.Const(4, false)
│   %3 = Core.apply_type(Main.AbstractCompressibleEuler, %1, %2, $(Expr(:static_parameter, 2)))::Core.Compiler.Const(AbstractCompressibleEuler{2,4,Float64}, false)
│   %4 = (%3)(gamma)::AbstractCompressibleEuler{2,4,Float64}
└──      return %4

julia> CompressibleEuler1D = AbstractCompressibleEuler{1}
AbstractCompressibleEuler{1,V,T} where T where V

julia> eq = CompressibleEuler1D(1.4)
AbstractCompressibleEuler{1,3,Float64}(1.4)

julia> @code_warntype CompressibleEuler1D(1.4)
Variables
  #self#::Type{AbstractCompressibleEuler{1,V,T} where T where V}
  gamma::Float64

Body::AbstractCompressibleEuler{1,3,Float64}
1 ─ %1 = $(Expr(:static_parameter, 1))::Core.Compiler.Const(1, false)
│   %2 = ($(Expr(:static_parameter, 1)) + 2)::Core.Compiler.Const(3, false)
│   %3 = Core.apply_type(Main.AbstractCompressibleEuler, %1, %2, $(Expr(:static_parameter, 2)))::Core.Compiler.Const(AbstractCompressibleEuler{1,3,Float64}, false)
│   %4 = (%3)(gamma)::AbstractCompressibleEuler{1,3,Float64}
└──      return %4

julia> function foo(eq::CompressibleEuler1D)
           eq.gamma
       end
foo (generic function with 1 method)

julia> foo(eq)
1.4

julia> @code_warntype foo(eq)
Variables
  #self#::Core.Compiler.Const(foo, false)
  eq::AbstractCompressibleEuler{1,3,Float64}

Body::Float64
1 ─ %1 = Base.getproperty(eq, :gamma)::Float64
└──      return %1
sloede commented 4 years ago

I think this looks very good! However, in the spirit of one framework, multiple solvers, I suggest to make AbstractCompressibleEulerEquations really abstract and instead duplicate the gamma part for each dimension. This way, everything for one dimension is really inside a single folder, including the struct.

ranocha commented 4 years ago

Okay, that's also fine with me. Then we would have something along the lines of

julia> abstract type AbstractEquation{NDIMS, V, T<:Real} end

julia> abstract type CompressibleEulerEquations{NDIMS, V, T} end

julia> struct CompressibleEulerEquations1D{T} <: CompressibleEulerEquations{1, 3, T}
           gamma::T
       end

julia> function CompressibleEulerEquations{NDIMS}(gamma) where {NDIMS}
           # this is something that is needed in the current framework if we don't specify the
           # equations and mesh completely but have to read an additional parameter ndims
           if NDIMS == 1
               CompressibleEulerEquations1D(gamma)
           elseif NDIMS == 2
               CompressibleEulerEquations2D(gamma)
           elseif NDIMS == 3
               CompressibleEulerEquations1D(gamma)
           else
               throw(ArgumentError("$NDIMS dimensions not supported."))
           end
       end

julia> @code_warntype CompressibleEulerEquations{1}(1.4)
Variables
  #self#::Type{CompressibleEulerEquations{1,V,T} where T where V}
  gamma::Float64

Body::CompressibleEulerEquations1D{Float64}
1 ─ %1 = ($(Expr(:static_parameter, 1)) == 1)::Core.Compiler.Const(true, false)
│        %1
│   %3 = Main.CompressibleEulerEquations1D(gamma)::CompressibleEulerEquations1D{Float64}
└──      return %3
2 ─      Core.Compiler.Const(:($(Expr(:static_parameter, 1)) == 2), false)
│        Core.Compiler.Const(:(%5), false)
│        Core.Compiler.Const(:(Main.CompressibleEulerEquations2D(gamma)), false)
│        Core.Compiler.Const(:(return %7), false)
│        Core.Compiler.Const(:($(Expr(:static_parameter, 1)) == 3), false)
│        Core.Compiler.Const(:(%9), false)
│        Core.Compiler.Const(:(Main.CompressibleEulerEquations1D(gamma)), false)
│        Core.Compiler.Const(:(return %11), false)
│        Core.Compiler.Const(:(Base.string($(Expr(:static_parameter, 1)), " dimensions not supported.")), false)
│        Core.Compiler.Const(:(Main.ArgumentError(%13)), false)
│        Core.Compiler.Const(:(Main.throw(%14)), false)
└──      Core.Compiler.Const(:(return %15), false)

julia> Base.ndims(::AbstractEquation{NDIMS, V, T}) where {NDIMS, V, T} = NDIMS

julia> nvariables(::AbstractEquation{NDIMS, V, T}) where {NDIMS, V, T} = V # Shall we rename V to NVARS?
nvariables (generic function with 1 method)

julia> Base.eltype(::AbstractEquation{NDIMS, V, T}) where {NDIMS, V, T} = T
sloede commented 4 years ago

This looks good to me! Is it really required to have

julia> function CompressibleEulerEquations{NDIMS}(gamma) where {NDIMS}
...

three times or is this just an artifact from copy-paste?

ranocha commented 4 years ago

It's indeed an artifact - I've fixed that, thanks!

sloede commented 4 years ago
julia> nvariables(::AbstractEquation{NDIMS, V, T}) where {NDIMS, V, T} = V # Shall we rename V to NVARS?

Yes!