Using orthogonal collocation method solve PDE of adsorption chromatography model

Chromatographic equation with diffusion:

\frac{\partial c}{\partial t} + \frac{1 - \epsilon}{\epsilon} \frac{\partial q}{\partial t} + u \frac{\partial c}{\partial x} = D \frac{\partial^2 c}{\partial x^2}
\frac{\partial q}{\partial t} = - k_f \left( q - \frac{q_m b c}{1 + b c} \right)

Initial conditions:

t = 0, c(x, 0) = q(x, 0) = 0, x > 0

Boundary conditions:

x = 0,

D \frac{\partial c}{\partial x} = u*(c - c0)

x = L,

D \frac{\partial c}{\partial x} = 0

Parameters:

L = 20       # Length of bed ,cm
ϵ = 0.4436   # bed porosity
c0 = 8.8     # Initial concentration ,mg/ml
qm = 76.85   # maximum adsorption capacity ,mg/ml
b = 0.0258   # Langmuir isotherm constant 
u = 0.0424   # Velocity ,cm/s
k_f = 0.89   # mass transfer coefficient ,s-1  
D = 2.69e-4  # Axial diffusion coefficient ,cm2/s 

Discretize the spatial variables using the finite element orthogonal collection method, and divide the column into 30 finite elements, each with 2 configuration points, and solve the pde.

There are some tutorials using Matlab to solve the similar questions:

Solved Multicomponent PDE-ODE System Using MATLAB - Adsorption

The Simple Breakthrough Curve Adsorption using One PDE with Intrinsic Adsorption Coefficient

I’m not sure whether the method they used is orthogonal collection.

Somebody kindly help me out this problem?

1 Like
using MethodOfLines, ModelingToolkit, DomainSets

function test(L::Float64, T::Float64)
    @parameters t, x
    @variables q(..), c(..)  

    ∂t = Differential(t) 
    ∂x = Differential(x)
    ∂xx = Differential(x)^2
    
    ϵ = 0.4436 
    b = 0.0258
    k_f = 0.89
    D = 2.69e-4
    u = 0.0424
    qm = 76.85
    c0 = 8.8

    eq = [
        0 ~ D * ∂xx(c(t, x)) + ∂t(c(t, x)) + (1 - ϵ) / ϵ * ∂t(q(t, x)) + u * ∂x(c(t, x)),
        0 ~ ∂t(q(t, x)) + k_f * (q(t, x) + qm * b * c(t, x) / (1 + b * c(t, x)))
    ]

    domain = [x ∈ Interval(0.0, L),
            t ∈ Interval(0.0, T)
    ]

    ic_bc = [
        # initial conditions
        q(0.0, x) ~ 0.0,
        c(0.0, x) ~ 0.0,
        # boundary conditions
        ∂x(c(t, 0)) ~ u * (c(t, x) - c0) / D,
        ∂x(c(t, L)) ~ 0.0
    ]

    @named pde_system = PDESystem(
        eq, ic_bc, domain, 
        [t, x], 
        [q(t, x), c(t, x)]
    )
    return pde_system
end

pde_system = test(20.0, 600.0)    

x, t = pde_system.ivs

q, c = pde_system.dvs

dx = 1.0

discretization = MOLFiniteDifference([x => dx], t, approx_order = 2)

prob = discretize(pde_system, discretization)

ERROR: ArgumentError: Upper boundary condition Differential(x)(c(t, 20.0)) ~ 0.0 on time variable is not supported, please use a change of variables t => -τ to make this an initial condition.

Stacktrace:

  1. (::MethodOfLines.var"#521#523"{…})(ic::PDEBase.UpperBoundary) at generate_ic_defaults.jl
  2. _mapreduce(f::MethodOfLines.var"#521#523"{…}, op::typeof(vcat), ::IndexLinear, A::Vector{…}) at reduce.jl
  3. _mapreduce_dim(f::Function, op::Function, ::Base._InitialValue, A::Vector{Any}, ::Colon) at reducedim.jl
  4. #mapreduce#821 at reducedim.jl
  5. mapreduce at reducedim.jl
  6. generate_ic_defaults(tconds::Vector{…}, s::MethodOfLines.DiscreteSpace{…}, ::MOLFiniteDifference{…}) at generate_ic_defaults.jl
  7. symbolic_discretize(pdesys::PDESystem, discretization::MOLFiniteDifference{…}) at symbolic_discretize.jl
  8. discretize(pdesys::PDESystem, discretization::MOLFiniteDifference{…}; analytic::Nothing, kwargs::Base.Pairs{…}) at discretization_state.jl
  9. discretize(pdesys::PDESystem, discretization::MOLFiniteDifference{…}) at discretization_state.jl

what does this mean? how to change variable t => -τ ?

using DifferentialEquations, Plots  

sol = solve(prob, saveat = 1.0)

I think that this error is misleading. I believe that this is related to an issue addressed by @xtalax in Dec 2022: Space varying parameter in PDE with ModelingToolkit

"
I think the condition for that error is erroneously including bcs in space that are on the upper end of the domain when they have time derivs, while it is only supposed to be thrown for final conditions in time.

Conditions like this one used to work before I changed the way initial conditions were parsed, and added this error message - the underlying discretization hasn’t changed though. This is a 10 line fix, I can get on this once I’m done debugging integrals
"

I’ve replicated this myself and get the same error.

I believe that the error is referring to the transformation τ=T−t, known as the “backward time” or “time reversal” technique, which is a common method used in solving PDEs with final time conditions like c(t=t_final). This is a strange request given that there are no final time conditions, but let’s lay out the details of this technique (as I understand it) incase I am missing something.

This change of variables effectively reverses the time direction, where:

  • τ is the new time variable
  • T is the final time
  • t is the original time variable

This means that:

  • When t = 0 (start of original time), τ = T
  • When t = T (end of original time), τ = 0

This converts a condition at the final time, t=T, into an initial condition, τ = 0.

Let’s consider how this transformation affects our PDE and its conditions:

  1. PDE Equation:
    The original PDE ∂u/∂t = … becomes -∂u/∂τ = …
    (The negative sign appears due to the chain rule: ∂u/∂t = ∂u/∂τ * ∂τ/∂t = -∂u/∂τ)
  2. Initial Condition:
    The original final condition at t = T becomes the initial condition at τ = 0
  3. Boundary Conditions:
    Spatial boundary conditions remain the same, but are now expressed in terms of τ

This allows the use of standard time-marching schemes (forward in τ).

However, this is clearly not very useful in our case since we are concerned with a boundary condition in space, not time. Furthermore, our initial conditions q(t=0, x)=0 and c(t=0, x)=0 will both become final time conditions w.r.t. τ with this transformation.

Nonetheless, I implemented the change of variables. This time, I expected that the two transformed initial conditions (w.r.t. “t”) to cause the final time error, rather than the spatial boundary condition. To my surprise, I get exactly the same error triggered by the spatial boundary condition at the outlet.

ERROR: ArgumentError: Upper boundary condition Differential(x)(c(τ, 20.0)) ~ 0.0 on time variable is not supported, please use a change of variables `t => -τ` to make this an initial condition.
Stacktrace:
 [1] (::MethodOfLines.var"#521#523"{…})(ic::PDEBase.UpperBoundary)
   @ MethodOfLines ~/.julia/packages/MethodOfLines/iIYN1/src/discretization/generate_ic_defaults.jl:7
 [2] _mapreduce(f::MethodOfLines.var"#521#523"{…}, op::typeof(vcat), ::IndexLinear, A::Vector{…})
   @ Base ./reduce.jl:440
 [3] _mapreduce_dim(f::Function, op::Function, ::Base._InitialValue, A::Vector{Any}, ::Colon)
   @ Base ./reducedim.jl:365
 [4] mapreduce
   @ ./reducedim.jl:357 [inlined]
 [5] generate_ic_defaults(tconds::Vector{…}, s::MethodOfLines.DiscreteSpace{…}, ::MOLFiniteDifference{…})
   @ MethodOfLines ~/.julia/packages/MethodOfLines/iIYN1/src/discretization/generate_ic_defaults.jl:5
 [6] symbolic_discretize(pdesys::PDESystem, discretization::MOLFiniteDifference{…})
   @ PDEBase ~/.julia/packages/PDEBase/nzap9/src/symbolic_discretize.jl:84
 [7] discretize(pdesys::PDESystem, discretization::MOLFiniteDifference{…}; analytic::Nothing, kwargs::@Kwargs{})
   @ PDEBase ~/.julia/packages/PDEBase/nzap9/src/discretization_state.jl:58
 [8] discretize(pdesys::PDESystem, discretization::MOLFiniteDifference{…})
   @ PDEBase ~/.julia/packages/PDEBase/nzap9/src/discretization_state.jl:55
 [9] top-level scope
   @ ~/Dev/github_projects/julia/ModelingToolkit-practice/models/chromatography/change_vars.jl:62
Some type information was truncated. Use `show(err)` to see complete types.

This leads me to suspect @xtalax original hypothesis: “the condition for that error is erroneously including bcs in space that are on the upper end of the domain when they have time derivs, while it is only supposed to be thrown for final conditions in time.”

@Stephen I believe I caught a mistake in your inlet boundary condition, where:

∂x(c(t, 0)) ~ u * (c(t, x) - c0) / D,

should be

∂x(c(t, 0)) ~ u * (c(t, 0) - c0) / D,

but it will still yield the same error of course.

I happen to be modeling chromatography in Julia, too, including more advanced models and would be interested in collaborating. I’m especially interested in making these into MTK model components that can be connected in an equation oriented flowsheet. Send me a message if you’re interested and perhaps we can find a solution faster, together.
https://www.linkedin.com/in/samuel-m-andersson/

Here is my refactor of @Stephen 's code for a change of variables incase it is helpful for debugging purposes. It does not include a re-transform back to the original forward time “t” coordinate system.

using MethodOfLines, ModelingToolkit, DomainSets, OrdinaryDiffEq, Plots

function test(L::Float64, T::Float64)
    @parameters τ, x
    @variables q(..), c(..)  

    ∂τ = Differential(τ) 
    ∂x = Differential(x)
    ∂xx = Differential(x)^2
    
    ϵ = 0.4436 
    b = 0.0258
    k_f = 0.89
    D = 2.69e-4
    u = 0.0424
    qm = 76.85
    c0 = 8.8

    eq = [
        0 ~ D * ∂xx(c(τ, x)) - ∂τ(c(τ, x)) + (1 - ϵ) / ϵ * (-∂τ(q(τ, x))) + u * ∂x(c(τ, x)),
        0 ~ -∂τ(q(τ, x)) + k_f * (q(τ, x) + qm * b * c(τ, x) / (1 + b * c(τ, x)))
    ]

    domain = [x ∈ Interval(0.0, L),
              τ ∈ Interval(0.0, T)
    ]

    ic_bc = [
        # initial conditions
        q(T, x) ~ 0.0,
        c(T, x) ~ 0.0,
        # boundary conditions
        ∂x(c(τ, 0)) ~ u * (c(τ, 0) - c0) / D,
        ∂x(c(τ, L)) ~ 0.0
    ]

    @named pde_system = PDESystem(
        eq, ic_bc, domain, 
        [τ, x], 
        [q(τ, x), c(τ, x)]
    )
    return pde_system
end

println("Start")
println()

pde_system = test(20.0, 60.0)    

x, τ = pde_system.ivs

q, c = pde_system.dvs

dx = 0.1

println("init discretizer")
println()
discretization = MOLFiniteDifference([x => dx], τ, approx_order = 2)

println("Start disc")
println()
prob = discretize(pde_system, discretization)

println("Start solve")
println()
# Solve ODE problem
sol = solve(prob, Tsit5(), saveat=0.2)

Yes, there are more mistakes:

eq = [
        0 ~ D * ∂xx(c(t, x)) + ∂t(c(t, x)) + (1 - ϵ) / ϵ * ∂t(q(t, x)) + u * ∂x(c(t, x)),
        0 ~ ∂t(q(t, x)) + k_f * (q(t, x) + qm * b * c(t, x) / (1 + b * c(t, x)))
    ]

should be:

eq = [
        0 ~ - D * ∂xx(c(t, x)) + ∂t(c(t, x)) + (1 - ϵ) / ϵ * ∂t(q(t, x)) + u * ∂x(c(t, x)),
        0 ~ ∂t(q(t, x)) + k_f * (q(t, x) - qm * b * c(t, x) / (1 + b * c(t, x)))
    ]

thank you for pointing out.
While, I rewrite the PDEs into the Dimensionless form, and the
discretization step sucess, yet gets error when solving it

function test2()
    @parameters τ, ξ
    @variables q̃(..), c̃(..)  

    ∂τ = Differential(τ) 
    ∂ξ = Differential(ξ)
    ∂ξξ = Differential(ξ)^2
    
    ϵ = 0.4436 
    b = 0.0258
    k_f = 0.89
    D = 2.69e-4
    u = 0.0424
    qm = 76.85
    c0 = 8.8
    L = 20.0

    eq = [
        0 ~ - D / (L * u) * ∂ξξ(c̃(τ, ξ)) + ∂τ(c̃(τ, ξ)) + (1 - ϵ) / ϵ * qm / c0 * ∂τ(q̃(τ, ξ)) + ∂ξ(c̃(τ, ξ)),
        0 ~ u / L * ∂τ(q̃(τ, ξ)) + k_f * (q̃(τ, ξ) - b * c0 * c̃(τ, ξ) / (1 + b * c0 * c̃(τ, ξ)))
    ]

    domain = [ξ ∈ Interval(0.0, 1.0),
            τ ∈ Interval(0.0, 1.0)
    ]

    ic_bc = [
        # initial conditions
        q̃(0.0, ξ) ~ 0.0,
        c̃(0.0, ξ) ~ 0.0,
        # boundary conditions
        ∂ξ(c̃(τ, 0.0)) ~ u * L / D * (c̃(τ, 0.0) - 1),
        ∂ξ(c̃(τ, 1.0)) ~ 0.0
    ]

    @named pde_system = PDESystem(
        eq, ic_bc, domain, 
        [τ, ξ], 
        [q̃(τ, ξ), c̃(τ, ξ)]
    )
    return pde_system
end

pde_system2 = test2()    

τ, ξ = pde_system2.ivs

q̃, c̃ = pde_system2.dvs

dξ = 0.01

discretization = MOLFiniteDifference([ξ => dξ], τ, approx_order = 2)

prob2 = discretize(pde_system2, discretization)

using DifferentialEquations, Plots  

sol = solve(prob2, saveat = 1.0)

Error:

ERROR: MethodError: no method matching SciMLBase.PDETimeSeriesSolution(::SciMLBase.PDETimeSeriesSolution{Float64, 2, Dict{Num, Matrix{Float64}}, MethodOfLines.MOLMetadata{Val{true}(), MethodOfLines.DiscreteSpace{1, 2, MethodOfLines.CenterAlignedGrid}, MOLFiniteDifference{MethodOfLines.CenterAlignedGrid, MethodOfLines.ScalarizedDiscretization}, PDESystem, Base.RefValue{Any}, Nothing, MethodOfLines.ScalarizedDiscretization}, ODESolution{Float64, 2, Vector{Vector{Float64}}, Nothing, Nothing, Vector{Float64}, Vector{Vector{Vector{Float64}}}, ODEProblem{Vector{Float64}, Tuple{Float64, Float64}, true, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, ODEFunction{true, SciMLBase.AutoSpecialize, FunctionWrappersWrappers.FunctionWrappersWrapper{Tuple{FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{Float64}, Vector{Float64}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, Float64}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, Float64}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{Float64}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}}}, false}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, ModelingToolkit.ObservedFunctionCache{ODESystem}, Nothing, ODESystem, Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, MethodOfLines.MOLMetadata{Val{true}(), MethodOfLines.DiscreteSpace{1, 2, MethodOfLines.CenterAlignedGrid}, MOLFiniteDifference{MethodOfLines.CenterAlignedGrid, MethodOfLines.ScalarizedDiscretization}, PDESystem, Base.RefValue{Any}, Nothing, MethodOfLines.ScalarizedDiscretization}}, CompositeAlgorithm{1, Tuple{Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, Vern7{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, Rosenbrock23{1, false, Nothing, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!)}, Rodas5P{1, false, Nothing, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!)}, FBDF{5, 1, false, Nothing, NLNewton{Rational{Int64}, Rational{Int64}, Rational{Int64}, Rational{Int64}}, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, Nothing, Nothing, typeof(OrdinaryDiffEq.trivial_limiter!)}, FBDF{5, 1, false, KrylovJL{typeof(Krylov.gmres!), Int64, Tuple{}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}}, NLNewton{Rational{Int64}, Rational{Int64}, Rational{Int64}, Rational{Int64}}, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, Nothing, Nothing, typeof(OrdinaryDiffEq.trivial_limiter!)}}, OrdinaryDiffEq.AutoSwitchCache{Tuple{Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, Vern7{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}}, Tuple{Rosenbrock23{0, false, Nothing, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!)}, Rodas5P{0, false, Nothing, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!)}, FBDF{5, 0, false, Nothing, NLNewton{Rational{Int64}, Rational{Int64}, Rational{Int64}, Rational{Int64}}, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, Nothing, Nothing, typeof(OrdinaryDiffEq.trivial_limiter!)}, FBDF{5, 0, false, KrylovJL{typeof(Krylov.gmres!), Int64, Tuple{}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}}, NLNewton{Rational{Int64}, Rational{Int64}, Rational{Int64}, Rational{Int64}}, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, Nothing, Nothing, typeof(OrdinaryDiffEq.trivial_limiter!)}}, Rational{Int64}, Int64}}, OrdinaryDiffEq.InterpolationData{ODEFunction{true, SciMLBase.AutoSpecialize, FunctionWrappersWrappers.FunctionWrappersWrapper{Tuple{FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{Float64}, Vector{Float64}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, Float64}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, Float64}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{Float64}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}}}, false}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, ModelingToolk…
Stacktrace:

wrap_sol(sol::SciMLBase.PDETimeSeriesSolution{…}, metadata::MethodOfLines.MOLMetadata{…}) at pde_solutions.jl

wrap_sol(sol::SciMLBase.PDETimeSeriesSolution{…}) at basic_solutions.jl

solve(::ODEProblem{…}; sensealg::Nothing, u0::Nothing, p::Nothing, wrap::Val{…}, kwargs::Base.Pairs{…}) at solve.jl

kwcall(::@NamedTuple{…}, ::typeof(solve), ::ODEProblem{…}) at solve.jl

top-level scope at 吸附模型.jl

Some type information was truncated. Use show(err) to see complete types.

ERROR: MethodError: no method matching SciMLBase.PDETimeSeriesSolution(::SciMLBase.PDETimeSeriesSolution{Float64, 2, Dict{Num, Matrix{Float64}}, MethodOfLines.MOLMetadata{Val{true}(), MethodOfLines.DiscreteSpace{1, 2, MethodOfLines.CenterAlignedGrid}, MOLFiniteDifference{MethodOfLines.CenterAlignedGrid, MethodOfLines.ScalarizedDiscretization}, PDESystem, Base.RefValue{Any}, Nothing, MethodOfLines.ScalarizedDiscretization}, ODESolution{Float64, 2, Vector{Vector{Float64}}, Nothing, Nothing, Vector{Float64}, Vector{Vector{Vector{Float64}}}, ODEProblem{Vector{Float64}, Tuple{Float64, Float64}, true, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, ODEFunction{true, SciMLBase.AutoSpecialize, FunctionWrappersWrappers.FunctionWrappersWrapper{Tuple{FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{Float64}, Vector{Float64}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, Float64}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, Float64}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{Float64}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}}}, false}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, ModelingToolkit.ObservedFunctionCache{ODESystem}, Nothing, ODESystem, Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, MethodOfLines.MOLMetadata{Val{true}(), MethodOfLines.DiscreteSpace{1, 2, MethodOfLines.CenterAlignedGrid}, MOLFiniteDifference{MethodOfLines.CenterAlignedGrid, MethodOfLines.ScalarizedDiscretization}, PDESystem, Base.RefValue{Any}, Nothing, MethodOfLines.ScalarizedDiscretization}}, CompositeAlgorithm{1, Tuple{Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, Vern7{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, Rosenbrock23{1, false, Nothing, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!)}, Rodas5P{1, false, Nothing, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!)}, FBDF{5, 1, false, Nothing, NLNewton{Rational{Int64}, Rational{Int64}, Rational{Int64}, Rational{Int64}}, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, Nothing, Nothing, typeof(OrdinaryDiffEq.trivial_limiter!)}, FBDF{5, 1, false, KrylovJL{typeof(Krylov.gmres!), Int64, Tuple{}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}}, NLNewton{Rational{Int64}, Rational{Int64}, Rational{Int64}, Rational{Int64}}, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, Nothing, Nothing, typeof(OrdinaryDiffEq.trivial_limiter!)}}, OrdinaryDiffEq.AutoSwitchCache{Tuple{Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, Vern7{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}}, Tuple{Rosenbrock23{0, false, Nothing, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!)}, Rodas5P{0, false, Nothing, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!)}, FBDF{5, 0, false, Nothing, NLNewton{Rational{Int64}, Rational{Int64}, Rational{Int64}, Rational{Int64}}, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, Nothing, Nothing, typeof(OrdinaryDiffEq.trivial_limiter!)}, FBDF{5, 0, false, KrylovJL{typeof(Krylov.gmres!), Int64, Tuple{}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}}, NLNewton{Rational{Int64}, Rational{Int64}, Rational{Int64}, Rational{Int64}}, typeof(OrdinaryDiffEq.DEFAULT_PRECS), Val{:forward}, true, nothing, Nothing, Nothing, typeof(OrdinaryDiffEq.trivial_limiter!)}}, Rational{Int64}, Int64}}, OrdinaryDiffEq.InterpolationData{ODEFunction{true, SciMLBase.AutoSpecialize, FunctionWrappersWrappers.FunctionWrappersWrapper{Tuple{FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{Float64}, Vector{Float64}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, Float64}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, Float64}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{Float64}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}}, FunctionWrappers.FunctionWrapper{Nothing, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}, ModelingToolkit.MTKParameters{Tuple{}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out,), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x93074a10, 0x6bb1517a, 0xa37907ca, 0x8269ac06, 0xac705e1b), Expr}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x946e17d4, 0xc3196aa2, 0x9aeaaf8d, 0xc3eaeb20, 0xceee7418), Expr}}, ForwardDiff.Dual{ForwardDiff.Tag{DiffEqBase.OrdinaryDiffEqTag, Float64}, Float64, 1}}}}, false}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, ModelingToolk…
Stacktrace:

wrap_sol(sol::SciMLBase.PDETimeSeriesSolution{…}, metadata::MethodOfLines.MOLMetadata{…}) at pde_solutions.jl

wrap_sol(sol::SciMLBase.PDETimeSeriesSolution{…}) at basic_solutions.jl

solve(::ODEProblem{…}; sensealg::Nothing, u0::Nothing, p::Nothing, wrap::Val{…}, kwargs::Base.Pairs{…}) at solve.jl

kwcall(::@NamedTuple{…}, ::typeof(solve), ::ODEProblem{…}) at solve.jl

top-level scope at 吸附模型.jl

Some type information was truncated. Use show(err) to see complete types.
[/details]

Hi, I don’t know if this can help in anyway as it does not used the desired method (FD), however it might be sufficient to tackle this problem?

using Plots
function main()
    # Physical parameters
    L   = 20       # Length of bed ,cm
    ϵ   = 0.4436   # bed porosity
    ci  = 8.8      # Initial concentration ,mg/ml
    qm  = 76.85    # maximum adsorption capacity ,mg/ml
    b   = 0.0258   # Langmuir isotherm constant 
    u   = 0.0424   # Velocity ,cm/s
    k_f = 0.89     # mass transfer coefficient ,s-1  
    D   = 2.69e-4  # Axial diffusion coefficient ,cm2/s 
    # Numerical parameters
    ncx = 100
    Δx  = L/(ncx)
    Δt  = 3e-1
    nt  = 2000
    nit = 3
    # Grid and arrays allocations
    xc  = LinRange(Δx/2, L-Δx/2, ncx)
    c   = zeros(ncx+2) # includes 2 ghosts cells
    c0  = zeros(ncx+2)
    q   = zeros(ncx)
    q0  = zeros(ncx)
    # Time loop
    @views for it=1:nt
        @. c0 = c
        @. q0 = q
        # Iteration loop
        for iter = 1:nit
            # Boundaries
            c[end] = c[end-1]
            c[1]   = c[2] - Δx*u/D*(0.5*(c[2]) - ci)
            # Update balance laws
            @. c[2:end-1] = c0[2:end-1] + Δt*(D*(c[1:end-2] + c[3:end-0] - 2.0.*c[2:end-1])/Δx^2 - (1.0-ϵ)/ϵ*(q-q0)/Δt - (u>0)*u*(c[2:end-1] - c[1:end-2])/Δx)
            @. q          = q0          + Δt*(-k_f*(q - (qm*b*c[2:end-1])/(1.0 + b*c[2:end-1])) )
        end
        # Visualise
        if mod(it, 100) == 0
            p = plot(xlabel = "x", ylabel="c, q", ylims=(0,25))
            p = plot!(xc, c[2:end-1], label="c")
            p = plot!(xc, q, label="q")
            display(p)
            sleep(0.05)
        end
    end
end

main()
1 Like