Skip to content
This repository was archived by the owner on Jul 19, 2023. It is now read-only.
This repository was archived by the owner on Jul 19, 2023. It is now read-only.

Discretize MOLFiniteDifference with more than one dependent variable #374

@michaelsachs

Description

@michaelsachs

I am trying to use ModelingToolkit for a 1D diffusion simulation with more than one dependent variable, but am getting a BoundsError when discretizing using MOLFiniteDifference.

The following code with one dependent variable works fine:

using OrdinaryDiffEq, ModelingToolkit, DiffEqOperators

# Parameters, variables, and derivatives
@parameters t x
@variables n(..) 
Dt = Differential(t)
Dx = Differential(x)
Dxx = Differential(x)^2

# 1D PDE and boundary conditions
eqs  = Dt(n(t,x)) ~ Dxx(n(t,x))

bcs = [n(0,x) ~ 2x,
        Dx(n(t,0)) ~ 0,
        Dx(n(t,10)) ~ 0]

# Space and time domains
domains = [t ∈ IntervalDomain(0.0,100.0),
           x ∈ IntervalDomain(0.0,10.0)]

# PDE system
pdesys = PDESystem(eqs,bcs,domains,[t,x],[n(t,x)])

# Method of lines discretization
Δx = 0.1
discretization = MOLFiniteDifference([x=>Δx],t)

# Convert the PDE problem into an ODE problem
prob = discretize(pdesys,discretization)

# Solve ODE problem
@time sol = solve(prob,Tsit5(),saveat=1.0)

However, when adding a second dependent variable (while keeping the system 1D) I am getting a BoundsError in the discretize(pdesys,discretization) step:

using OrdinaryDiffEq, ModelingToolkit, DiffEqOperators

# Parameters, variables, and derivatives
@parameters t x
@variables n(..) p(..)
Dt = Differential(t)
Dx = Differential(x)
Dxx = Differential(x)^2

# 1D PDE and boundary conditions
eqs  = [Dt(n(t,x)) ~ Dxx(n(t,x)),
        Dt(p(t,x)) ~ Dxx(p(t,x))]

bcs = [n(0,x) ~ 2x,
        Dx(n(t,0)) ~ 0,
        Dx(n(t,10)) ~ 0,
        p(0,x) ~ 2x,
        Dx(p(t,0)) ~ 0,
        Dx(p(t,10)) ~ 0]

# Space and time domains
domains = [t ∈ IntervalDomain(0.0,100.0),
           x ∈ IntervalDomain(0.0,10.0)]

# PDE system
pdesys = PDESystem(eqs,bcs,domains,[t,x],[n(t,x),p(t,x)])

# Method of lines discretization
Δx = 0.1
discretization = MOLFiniteDifference([x=>Δx],t)

# Convert the PDE problem into an ODE problem
prob = discretize(pdesys,discretization)

# Solve ODE problem
@time sol = solve(prob,Tsit5(),saveat=1.0)

With the stacktrace being as follows:

ERROR: LoadError: BoundsError: attempt to access 1-element Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}} at index [2]
Stacktrace:
  [1] getindex
    @ .\array.jl:801 [inlined]
  [2] left_weights
    @ ~\.julia\packages\DiffEqOperators\Fmo6r\src\MOLFiniteDifference\MOL_discretization.jl:57 [inlined]
  [3] (::DiffEqOperators.var"#204#243"{DiffEqOperators.var"#right_idxs#242"{Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}, Vector{CartesianIndex{1}}, DiffEqOperators.var"#right_weights#238"{MOLFiniteDifference{Vector{Pair{Num, Float64}}, Num}, Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}, DiffEqOperators.var"#left_weights#237"{MOLFiniteDifference{Vector{Pair{Num, Float64}}, Num}, Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}})(::Tuple{Int64, Vector{Num}})
    @ DiffEqOperators .\none:0
  [4] iterate
    @ .\generator.jl:47 [inlined]
  [5] collect_to!(dest::Vector{Vector{Num}}, itr::Base.Generator{Base.Iterators.Enumerate{Vector{Vector{Num}}}, DiffEqOperators.var"#204#243"{DiffEqOperators.var"#right_idxs#242"{Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}, Vector{CartesianIndex{1}}, DiffEqOperators.var"#right_weights#238"{MOLFiniteDifference{Vector{Pair{Num, Float64}}, Num}, Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}, DiffEqOperators.var"#left_weights#237"{MOLFiniteDifference{Vector{Pair{Num, Float64}}, Num}, Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}}}, offs::Int64, st::Tuple{Int64, Int64})
    @ Base .\array.jl:724
  [6] collect_to_with_first!(dest::Vector{Vector{Num}}, v1::Vector{Num}, itr::Base.Generator{Base.Iterators.Enumerate{Vector{Vector{Num}}}, DiffEqOperators.var"#204#243"{DiffEqOperators.var"#right_idxs#242"{Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}, Vector{CartesianIndex{1}}, DiffEqOperators.var"#right_weights#238"{MOLFiniteDifference{Vector{Pair{Num, Float64}}, Num}, Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}, DiffEqOperators.var"#left_weights#237"{MOLFiniteDifference{Vector{Pair{Num, Float64}}, Num}, Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}}}, st::Tuple{Int64, Int64})
    @ Base .\array.jl:702
  [7] collect(itr::Base.Generator{Base.Iterators.Enumerate{Vector{Vector{Num}}}, DiffEqOperators.var"#204#243"{DiffEqOperators.var"#right_idxs#242"{Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}, Vector{CartesianIndex{1}}, DiffEqOperators.var"#right_weights#238"{MOLFiniteDifference{Vector{Pair{Num, Float64}}, Num}, Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}, DiffEqOperators.var"#left_weights#237"{MOLFiniteDifference{Vector{Pair{Num, Float64}}, Num}, Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}}}})
    @ Base .\array.jl:683
  [8] symbolic_discretize(pdesys::PDESystem, discretization::MOLFiniteDifference{Vector{Pair{Num, Float64}}, Num})
    @ DiffEqOperators ~\.julia\packages\DiffEqOperators\Fmo6r\src\MOLFiniteDifference\MOL_discretization.jl:63
  [9] discretize(pdesys::PDESystem, discretization::MOLFiniteDifference{Vector{Pair{Num, Float64}}, Num})
    @ DiffEqOperators ~\.julia\packages\DiffEqOperators\Fmo6r\src\MOLFiniteDifference\MOL_discretization.jl:152

Looking into MOL_discretization.jl, the problem seems to be that space is a one element vector when it should contain two elements for the following piece of code to run successfully (as depvars also contains two elements). Not sure if this is a bug or just me getting the syntax wrong?

# 1D system
left_weights(j) = DiffEqOperators.calculate_weights(discretization.upwind_order, space[j][1], space[j][1:2])
right_weights(j) = DiffEqOperators.calculate_weights(discretization.upwind_order, space[j][end], space[j][end-1:end])
central_neighbor_idxs(i,j) = [i+CartesianIndex([ifelse(l==j,-1,0) for l in 1:nspace]...),i,i+CartesianIndex([ifelse(l==j,1,0) for l in 1:nspace]...)]
left_idxs = central_neighbor_idxs(CartesianIndex(2),1)[1:2]
right_idxs(j) = central_neighbor_idxs(CartesianIndex(length(space[j])-1),1)[end-1:end]
# Constructs symbolic spatially discretized terms of the form e.g. au₂ - bu₁
derivars = [[dot(left_weights(j),depvar[left_idxs]), dot(right_weights(j),depvar[right_idxs(j)])]
            for (j, depvar) in enumerate(depvars)]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions