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

Commit 50dc585

Browse files
Merge remote-tracking branch 'origin/master'
2 parents 96c534b + c9205f0 commit 50dc585

File tree

5 files changed

+95
-2
lines changed

5 files changed

+95
-2
lines changed

docs/KdV.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Solving the Heat Equation using DiffEqOperators
1+
# Solving the KdV Equation using DiffEqOperators
22

33
In this tutorial we will try to solve the famous **KdV equation** which describes the motion of waves on shallow water surfaces.
44
The equation is commonly written as
@@ -29,4 +29,4 @@ Now call the ODE solver as follows:-
2929
sol1 = solve(prob1, dense=false, tstops=0:0.01:10);
3030

3131
and plot the solutions to see the waveform evolve with time.
32-
**Note:** The waveform being solved for here is non-directional unlike the many waves you might see like traveling solitons. In that case you might need to use the Upwind operators.
32+
**Note:** The waveform being solved for here is non-directional unlike the many waves you might see like traveling solitons. In that case you might need to use the Upwind operators.

src/DiffEqOperators.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ using SparseArrays
88

99
abstract type AbstractDerivativeOperator{T} <: AbstractDiffEqLinearOperator{T} end
1010
abstract type AbstractDiffEqCompositeOperator{T} <: AbstractDiffEqLinearOperator{T} end
11+
abstract type AbstractMatrixFreeOperator{T} <: AbstractDiffEqLinearOperator{T} end
1112

1213
### Common default methods for the operators
1314
include("common_defaults.jl")
1415

1516
### Basic Operators
1617
include("basic_operators.jl")
1718

19+
### Matrix-free Operators
20+
include("matrixfree_operators.jl")
21+
1822
### Derivative Operators
1923
include("derivative_operators/fornberg.jl")
2024
include("derivative_operators/upwind_operator.jl")
@@ -33,6 +37,7 @@ for T in [DiffEqScalar, DiffEqArrayOperator, FactorizedDiffEqArrayOperator, Diff
3337
(L::T)(du,u,p,t) = (update_coefficients!(L,u,p,t); mul!(du,L,u))
3438
end
3539

40+
export MatrixFreeOperator
3641
export DiffEqScalar, DiffEqArrayOperator, DiffEqIdentity, getops
3742
export AbstractDerivativeOperator, DerivativeOperator, UpwindOperator, FiniteDifference
3843
end # module

src/matrixfree_operators.jl

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import LinearAlgebra: mul!
2+
struct MatrixFreeOperator{F,N} <: AbstractMatrixFreeOperator{F}
3+
f::F
4+
args::N
5+
function MatrixFreeOperator(f::F, args::N) where {F,N}
6+
@assert N === Nothing || (N <: Tuple && length(args) == 2) "Arguments of a "*
7+
"MatrixFreeOperator must be nothing or a tuple with two elements"
8+
return new{F,N}(f, args)
9+
end
10+
end
11+
MatrixFreeOperator(f) = MatrixFreeOperator(f, nothing)
12+
13+
function Base.getproperty(M::MatrixFreeOperator{F,N}, sym::Symbol) where {F,N}
14+
if sym === :update_func
15+
return N === Nothing ? DEFAULT_UPDATE_FUNC : M.f
16+
else
17+
return getfield(M, sym)
18+
end
19+
end
20+
21+
function (M::MatrixFreeOperator{F,N})(du, u, p, t) where {F,N}
22+
if N === Nothing
23+
M.f(du, u)
24+
else
25+
M.f(du, u, p, t)
26+
end
27+
du
28+
end
29+
30+
function (M::MatrixFreeOperator{F,N})(u, p, t) where {F,N}
31+
du = similar(u)
32+
if N === nothing
33+
M.f(du, u)
34+
else
35+
M.f(du, u, p, t)
36+
end
37+
du
38+
end
39+
40+
@inline function mul!(y::AbstractVector, A::MatrixFreeOperator{F,N}, x::AbstractVector) where {F,N}
41+
if N === Nothing
42+
A.f(y, x)
43+
else
44+
A.f(y, x, A.args[1], A.args[2])
45+
end
46+
y
47+
end
48+
49+
@inline function mul!(Y::AbstractMatrix, A::MatrixFreeOperator{F,N}, X::AbstractMatrix) where {F,N}
50+
m, n = size(Y)
51+
k, _n = size(X)
52+
if n != _n
53+
throw(DimensionMismatch("the second dimension of Y, $N, does not match the second dimension of X, $_n"))
54+
end
55+
for i in 1:n
56+
y = view(Y, :, i)
57+
x = view(X, :, i)
58+
mul!(y, A, x)
59+
end
60+
Y
61+
end
62+
@inline Base.:*(A::MatrixFreeOperator, X::AbstractVecOrMat) = mul!(similar(X), A, X)
63+
64+
DiffEqBase.numargs(::MatrixFreeOperator) = 4

test/matrixfree.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Test, LinearAlgebra
2+
using DiffEqOperators, OrdinaryDiffEq
3+
4+
@testset "Matrix Free Operator" begin
5+
f = cumsum!
6+
A = MatrixFreeOperator(f)
7+
b = rand(5)
8+
prob = ODEProblem(A, b, (0,1.))
9+
@test_nowarn solve(prob, Tsit5())
10+
prob = SplitODEProblem(A, (du,u,p,t)->0, b, (0,1.))
11+
Base.size(::typeof(A), n) = n==1 || n == 2 ? 5 : 1
12+
LinearAlgebra.opnorm(::typeof(A), n::Real) = n==Inf ? 5 : nothing
13+
LinearAlgebra.ishermitian(::typeof(A)) = false
14+
@test_nowarn solve(prob, LawsonEuler(krylov=true, m=5), dt=0.1)
15+
f = (du, u, p, t) -> cumsum!(du, u)
16+
args = (1, 1)
17+
A = MatrixFreeOperator(f,args)
18+
b = rand(5)
19+
Base.size(::typeof(A), n) = n==1 || n == 2 ? 5 : 1
20+
LinearAlgebra.opnorm(::typeof(A), n::Real) = n==Inf ? 5 : nothing
21+
LinearAlgebra.ishermitian(::typeof(A)) = false
22+
@test_nowarn solve(prob, LawsonEuler(krylov=true, m=5), dt=0.1)
23+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Base: isapprox
1414
@time @testset "Finite Difference Operator" begin include("generic_operator_check.jl") end
1515
#@time @testset "KdV" begin include("KdV.jl") end # KdV times out and all fails
1616
@time @testset "Heat Equation" begin include("heat_eqn.jl") end
17+
@time @testset "Matrix-Free Operators" begin include("matrixfree.jl") end
1718

1819

1920

0 commit comments

Comments
 (0)