Skip to content

Commit 3310e14

Browse files
Merge pull request #14 from yewalenikhil65/master
fornberg(2020) weights based on hermite-based finite difference
2 parents de64d60 + d71125e commit 3310e14

File tree

3 files changed

+64
-12
lines changed

3 files changed

+64
-12
lines changed

src/discretization/fornberg.jl

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
1-
#############################################################
2-
# Fornberg algorithm
3-
4-
# This implements the Fornberg (1988) algorithm (https://doi.org/10.1090/S0025-5718-1988-0935077-0)
5-
# to obtain Finite Difference weights over arbitrary points to arbitrary order.
6-
7-
function calculate_weights(order::Int, x0::T, x::AbstractVector) where T<:Real
8-
#=
1+
#= Fornberg algorithm
2+
This implements the Fornberg (1988) algorithm (https://doi.org/10.1090/S0025-5718-1988-0935077-0)
3+
and hermite-based finite difference Fornberg(2020) algorithm (https://doi.org/10.1093/imanum/draa006)
4+
to obtain Finite Difference weights over arbitrary points to arbitrary order.
5+
Inputs:
96
order: The derivative order for which we need the coefficients
107
x0 : The point in the array 'x' for which we need the coefficients
118
x : A dummy array with relative coordinates, e.g., central differences
129
need coordinates centred at 0 while those at boundaries need
1310
coordinates starting from 0 to the end point
11+
dfdx : optional argument to consider weights of the first-derivative of function or not
12+
if dfdx == false (default kwarg), implies Fornberg(1988)
13+
dfdx == true, implies Fornberg(2020)
14+
Outputs:
15+
if dfdx == false (default kwarg), _C : weights to approximate derivative of required order using function values only.
16+
else, _D,_E : weights to approximate derivative of required order using function and its first-
17+
derivative values respectively.
18+
=#
1419

15-
The approximation order of the stencil is automatically determined from
16-
the number of requested stencil points.
17-
=#
20+
function calculate_weights(order::Int, x0::T, x::AbstractVector; dfdx::Bool = false) where T<:Real
1821
N = length(x)
1922
@assert order < N "Not enough points for the requested order."
2023
M = order
@@ -58,5 +61,23 @@ function calculate_weights(order::Int, x0::T, x::AbstractVector) where T<:Real
5861
if order != 0
5962
_C[div(N,2)+1] -= sum(_C)
6063
end
61-
return _C
64+
if dfdx == false
65+
return _C
66+
else
67+
A = x .- x';
68+
s = sum(1 ./ (A + I(N)), dims = 1) .- 1;
69+
cp = factorial.(0:M);
70+
cc = C./cp'
71+
= zeros(N, M+2);
72+
for k in 1:M+1
73+
c̃[:,k+1] = sum(cc[:,1:k].*cc[:,k:-1:1], dims = 2);
74+
end
75+
E = c̃[:,1:M+1] - (x .- x0).*c̃[:,2:M+2];
76+
D = c̃[:,2:M+2] + 2*E.*s';
77+
D = D.*cp';
78+
E = E.*cp';
79+
80+
_D = D[:,end]; _E = E[:,end]
81+
return _D, _E
82+
end
6283
end
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Test, LinearAlgebra
2+
using MethodOfLines
3+
4+
@testset "finite-difference weights from fornberg(1988) & fornberg(2020)" begin
5+
order = 2; z = 0.0; x = [-1, 0, 1.0];
6+
@test MethodOfLines.calculate_weights(order, z, x) == [1,-2,1] # central difference of second-derivative with unit-step
7+
8+
order = 1; z = 0.0; x = [-1., 1.0];
9+
@test MethodOfLines.calculate_weights(order, z, x) == [-0.5,0.5] # central difference of first-derivative with unit step
10+
11+
order = 1; z = 0.0; x = [0, 1];
12+
@test MethodOfLines.calculate_weights(order, z, x) == [-1, 1] # forward difference
13+
14+
order = 1; z = 1.0; x = [0, 1];
15+
@test MethodOfLines.calculate_weights(order, z, x) == [-1, 1] # backward difference
16+
17+
# forward-diff of third derivative with order of accuracy == 3
18+
order = 3; z = 0.0; x = [0,1,2,3,4,5]
19+
@test MethodOfLines.calculate_weights(order, z, x) == [-17/4, 71/4 ,59/2, 49/2, 41/4, 7/4]
20+
21+
order = 3; z = 0.0; x = collect(-3:3)
22+
d, e = MethodOfLines.calculate_weights(order, z, x;dfdx = true)
23+
@test d [-167/18000, -963/2000, -171/16,0,171/16,963/2000,167/18000]
24+
@test e [-1/600,-27/200,-27/8,-49/3,-27/8,-27/200,-1/600]
25+
26+
order = 3; z = 0.0; x = collect(-4:4)
27+
d, e = MethodOfLines.calculate_weights(order, z, x;dfdx = true)
28+
@test d [-2493/5488000, -12944/385875, -87/125 ,-1392/125,0,1392/125,87/125,12944/385875,2493/5488000]
29+
@test e [-3/39200,-32/3675,-6/25,-96/25,-205/12, -96/25, -6/25,-32/3675,-3/39200]
30+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const is_TRAVIS = haskey(ENV,"TRAVIS")
1717

1818
if GROUP == "All" || GROUP == "Integration Tests"
1919
@time @safetestset "MOLFiniteDifference Interface" begin include("pde_systems/MOLtest.jl") end
20+
@time @safetestset "MOLFiniteDifference Interface" begin include("pde_systems/MOLfornberg_weights.jl") end
2021
#@time @safetestset "MOLFiniteDifference Interface: Linear Convection" begin include("pde_systems/MOL_1D_Linear_Convection.jl") end
2122
@time @safetestset "MOLFiniteDifference Interface: 1D Linear Diffusion" begin include("pde_systems/MOL_1D_Linear_Diffusion.jl") end
2223
@time @safetestset "MOLFiniteDifference Interface: 1D Non-Linear Diffusion" begin include("pde_systems/MOL_1D_NonLinear_Diffusion.jl") end

0 commit comments

Comments
 (0)