Skip to content

Add support for WENO4 interpolation #470

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Interpolations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export
# extrapolation/extrapolation.jl
# monotonic/monotonic.jl
# scaling/scaling.jl
# weno/weno.jl

using LinearAlgebra, SparseArrays
using StaticArrays, WoodburyMatrices, Ratios, AxisAlgorithms, OffsetArrays
Expand Down Expand Up @@ -489,6 +490,7 @@ include("lanczos/lanczos_opencv.jl")
include("iterate.jl")
include("chainrules/chainrules.jl")
include("hermite/cubic.jl")
include("weno/weno.jl")

function __init__()
@require Unitful="1986cc42-f94f-5a68-af5c-568840ba703d" include("requires/unitful.jl")
Expand Down
200 changes: 200 additions & 0 deletions src/weno/weno.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
#=
Interpolate using weighted essentially non-oscillatory (WENO) techniques.
=#

export WENO4Interpolation


"""
WENOInterpolationType

Abstract class for all types of WENO interpolation.
"""
abstract type WENOInterpolationType <: InterpolationType end

"""
WENO4Interpolation

Fourth-order WENO interpolation. Based on Janett et al. (2019),
"A novel fourth-order WENO interpolation technique. A possible new tool designed for radiative transfer",
https://ui.adsabs.harvard.edu/abs/2019A&A...624A.104J
"""
struct WENO4Interpolation{T} <: WENOInterpolationType where T <: Number
nodes::Vector{T}
α2::Vector{T} # coefficients for the α2 and α3 weights
α3::Vector{T} # coefficients for the α2 and α3 weights
q2::Array{T, 2} # coefficients for the quadratic Lagrange polynomials q2
q3::Array{T, 2} # coefficients for the quadratic Lagrange polynomials q3
end

function Base.:(==)(o1::WENO4Interpolation, o2::WENO4Interpolation)
o1.nodes == o2.nodes &&

Check warning on line 31 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L30-L31

Added lines #L30 - L31 were not covered by tests
o1.α2 == o2.α2 &&
o1.α3 == o2.α3 &&
o1.q2 == o2.q2 &&
o1.q3 == o2.q3
end

lbounds(itp::WENO4Interpolation) = (first(itp.nodes),)
ubounds(itp::WENO4Interpolation) = (last(itp.nodes),)

Check warning on line 39 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L38-L39

Added lines #L38 - L39 were not covered by tests


function interpolate(nodes::AbstractVector{<:Number}, A::AbstractVector{<:Number})
n = length(nodes)
α2 = Vector{eltype(nodes)}(undef, n)
α3 = Vector{eltype(nodes)}(undef, n)
q2 = Array{eltype(nodes)}(undef, 3, n)
q3 = Array{eltype(nodes)}(undef, 3, n)

Check warning on line 47 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L42-L47

Added lines #L42 - L47 were not covered by tests

for i ∈ 1:n
xim, xi, xip, xipp = get_stencil_nodes(i, nodes)
yim, yi, yip, yipp = get_stencil_values(i, A)
q2[:, i], q3[:, i] = weno4_q(xim, xi, xip, xipp, yim, yi, yip, yipp)
α2[i], α3[i] = weno4_α(xim, xi, xip, xipp, yim, yi, yip, yipp)
end
WENO4Interpolation(nodes, α2, α3, q2, q3)

Check warning on line 55 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L49-L55

Added lines #L49 - L55 were not covered by tests
end


function (itp::WENO4Interpolation)(x::Number)
@boundscheck (checkbounds(Bool, itp, x) || Base.throw_boundserror(itp, (x,)))
n = length(itp.nodes)
i = binary_search(itp.nodes, x)
xim, xi, xip, xipp = get_stencil_nodes(i, itp.nodes)
Δim = x - xim
Δi = x - xi
Δip = x - xip
Δipp = x - xipp
q2 = itp.q2[1, i] * Δi * Δip + itp.q2[2, i] * Δim * Δip + itp.q2[3, i] * Δim * Δi
q3 = itp.q3[1, i] * Δip * Δipp + itp.q3[2, i] * Δi * Δipp + itp.q3[3, i] * Δi * Δip
if i == 1
result = q3
elseif i == n - 1
result = q2

Check warning on line 73 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L59-L73

Added lines #L59 - L73 were not covered by tests
else
α2 = Δipp * itp.α2[i]
α3 = Δip * itp.α3[i]
ω2 = α2 / (α2 + α3)
ω3 = α3 / (α2 + α3)
result = ω2 * q2 + ω3 * q3

Check warning on line 79 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L75-L79

Added lines #L75 - L79 were not covered by tests
end
return result

Check warning on line 81 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L81

Added line #L81 was not covered by tests
end


function get_stencil_nodes(index::Int, nodes::AbstractVector{<:Number})
n = length(nodes)
if index == n
index -= 1

Check warning on line 88 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L85-L88

Added lines #L85 - L88 were not covered by tests
end
xi = nodes[index]
xip = nodes[index+1]
if index == 1
xim = zero(eltype(nodes))
xipp = nodes[index+2]
elseif index == n - 1
xim = nodes[index-1]
xipp = zero(eltype(nodes))

Check warning on line 97 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L90-L97

Added lines #L90 - L97 were not covered by tests
else
xim = nodes[index-1]
xipp = nodes[index+2]

Check warning on line 100 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L99-L100

Added lines #L99 - L100 were not covered by tests
end
return (xim, xi, xip, xipp)

Check warning on line 102 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L102

Added line #L102 was not covered by tests
end


function get_stencil_values(index::Int, A::AbstractVector{<:Number})
n = length(A)
if index == n
index -= 1

Check warning on line 109 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L106-L109

Added lines #L106 - L109 were not covered by tests
end
yi = A[index]
yip = A[index+1]
if index == 1
yim = zero(eltype(A))
yipp = A[index+2]
elseif index == n - 1
yim = A[index-1]
yipp = zero(eltype(A))

Check warning on line 118 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L111-L118

Added lines #L111 - L118 were not covered by tests
else
yim= A[index-1]
yipp = A[index+2]

Check warning on line 121 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L120-L121

Added lines #L120 - L121 were not covered by tests
end
return (yim, yi, yip, yipp)

Check warning on line 123 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L123

Added line #L123 was not covered by tests
end


"""
binary_search(a::AbstractVector{<:Number}, x)

Return the index of the last value in `a` less than or equal to `x`.
`a` is assumed to be sorted.
"""
function binary_search(a::AbstractVector{<:Number}, x)
n = length(a)
ileft = 2
i = n - 1
while ileft <= i
mid = (ileft + i) >> 1
if @inbounds x < a[mid]
i = mid - 1

Check warning on line 140 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L133-L140

Added lines #L133 - L140 were not covered by tests
else
ileft = mid + 1

Check warning on line 142 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L142

Added line #L142 was not covered by tests
end
end
return i

Check warning on line 145 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L144-L145

Added lines #L144 - L145 were not covered by tests
end

"""
Compute the smoothness indicators β2 and β3 for 4th order WENO interpolation.
Arguments are the x and y values for the 4-point stencil.
"""
function weno4_α(xim, xi, xip, xipp, yim, yi, yip, yipp)
ε = 1.0f-6
him = xi - xim
hi = xip - xi
hip = xipp - xip
H = him + hi + hip

Check warning on line 157 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L152-L157

Added lines #L152 - L157 were not covered by tests
# Derivatives
yyim = -((2 * him + hi) * H + him * (him + hi)) / (him * (him + hi) * H) * yim
yyim += ((him + hi) * H) / (him * hi * (hi + hip)) * yi
yyim -= (him * H) / ((him + hi) * hi * hip) * yip
yyim += (him * (him + hi)) / ((hi + hip) * hip * H) * yipp
yyi = -(hi * (hi + hip)) / (him * (him + hi) * H) * yim
yyi += (hi * (hi + hip) - him * (2 * hi + hip)) / (him * hi * (hi + hip)) * yi
yyi += (him * (hi + hip)) / ((him + hi) * hi * hip) * yip
yyi -= (him * hi) / ((hi + hip) * hip * H) * yipp
yyip = (hi * hip) / (him * (him + hi) * H) * yim
yyip -= (hip * (him + hi)) / (him * hi * (hi + hip)) * yi
yyip += ((him + 2 * hi) * hip - (him + hi) * hi) / ((him + hi) * hi * hip) * yip
yyip += ((him + hi) * hi) / ((hi + hip) * hip * H) * yipp
yyipp = -((hi + hip) * hip) / (him * (him + hi) * H) * yim
yyipp += (hip * H) / (him * hi * (hi + hip)) * yi
yyipp -= ((hi + hip) * H) / ((him + hi) * hi * hip) * yip
yyipp += ((2 * hip + hi) * H + hip * (hi + hip)) / ((hi + hip) * hip * H) * yipp

Check warning on line 174 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L159-L174

Added lines #L159 - L174 were not covered by tests
# Smoothness indicators
β2 = (hi + hip)^2 * (abs(yyip - yyi) / hi - abs(yyi - yyim) / him)^2
β3 = (him + hi)^2 * (abs(yyipp - yyip) / hip - abs(yyip - yyi) / hi)^2
α2 = - one(typeof(xim)) / ((xipp - xim) * (ε + β2))
α3 = one(typeof(xim)) / ((xipp - xim) * (ε + β3))
return (α2, α3)

Check warning on line 180 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L176-L180

Added lines #L176 - L180 were not covered by tests
end

"""
Compute the q2 and q3 Lagrange interpolation factors for 4th order WENO interpolation.
Arguments are the x and y values for the 4-point stencil.
"""
function weno4_q(xim, xi, xip, xipp, yim, yi, yip, yipp)
him = xi - xim
hi = xip - xi
hip = xipp - xip
q2 = Vector{eltype(xim)}(undef, 3)
q3 = Vector{eltype(xim)}(undef, 3)
q2[1] = yim / (him * (him + hi))
q2[2] = -yi / (him * hi)
q2[3] = yip / ((him + hi) * hi)
q3[1] = yi / (hi * (hi + hip))
q3[2] = -yip / (hi * hip)
q3[3] = yipp / ((hi + hip) * hip)
return (q2, q3)

Check warning on line 199 in src/weno/weno.jl

View check run for this annotation

Codecov / codecov/patch

src/weno/weno.jl#L187-L199

Added lines #L187 - L199 were not covered by tests
end