|
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: |
9 | 6 | order: The derivative order for which we need the coefficients |
10 | 7 | x0 : The point in the array 'x' for which we need the coefficients |
11 | 8 | x : A dummy array with relative coordinates, e.g., central differences |
12 | 9 | need coordinates centred at 0 while those at boundaries need |
13 | 10 | 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 | +=# |
14 | 19 |
|
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) where T<:Real |
18 | 21 | N = length(x) |
19 | 22 | @assert order < N "Not enough points for the requested order." |
20 | 23 | M = order |
@@ -58,5 +61,23 @@ function calculate_weights(order::Int, x0::T, x::AbstractVector) where T<:Real |
58 | 61 | if order != 0 |
59 | 62 | _C[div(N,2)+1] -= sum(_C) |
60 | 63 | 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 | + c̃ = 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 |
62 | 83 | end |
0 commit comments