Skip to content

Commit a5fae78

Browse files
authored
fix pchip endpoints (#416)
1 parent d188ecd commit a5fae78

File tree

1 file changed

+23
-5
lines changed

1 file changed

+23
-5
lines changed

src/interpolation_utils.jl

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ function quadratic_spline_params(t::AbstractVector, sc::AbstractVector)
7070

7171
# Create linear system Ac = u, where:
7272
# - A consists of basis function evaulations in t
73-
# - c are 1D control points
73+
# - c are 1D control points
7474
n = length(t)
7575
dtype_sc = typeof(t[1] / t[1])
7676

@@ -235,6 +235,19 @@ function du_PCHIP(u, t)
235235
δ = diff(u) ./ h
236236
s = sign.(δ)
237237

238+
# Special handling of the slope at the endpoints, see
239+
# Cleve Moler, Numerical Computing with MATLAB, Chap 3.6 (file pchiptx.m, function pchipend())
240+
function _edge_case(h₁, h₂, δ₁, δ₂)
241+
d = ((2 * h₁ + h₂) * δ₁ - h₁ * δ₂) / (h₁ + h₂)
242+
if sign(d) != sign(δ₁)
243+
zero(eltype(δ))
244+
elseif sign(δ₁) != sign(δ₂) && abs(d) > 3 * abs(δ₁)
245+
3 * δ₁
246+
else
247+
d
248+
end
249+
end
250+
238251
function _du(k)
239252
sₖ₋₁, sₖ = if k == 1
240253
s[1], s[2]
@@ -248,17 +261,22 @@ function du_PCHIP(u, t)
248261
zero(eltype(δ))
249262
elseif sₖ₋₁ == sₖ
250263
if k == 1
251-
((2 * h[1] + h[2]) * δ[1] - h[1] * δ[2]) / (h[1] + h[2])
264+
_edge_case(h[1], h[2], δ[1], δ[2])
252265
elseif k == lastindex(t)
253-
((2 * h[end] + h[end - 1]) * δ[end] - h[end] * δ[end - 1]) /
254-
(h[end] + h[end - 1])
266+
_edge_case(h[end], h[end - 1], δ[end], δ[end - 1])
255267
else
256268
w₁ = 2h[k] + h[k - 1]
257269
w₂ = h[k] + 2h[k - 1]
258270
(w₁ + w₂) / (w₁ / δ[k - 1] + w₂ / δ[k])
259271
end
260272
else
261-
zero(eltype(δ))
273+
if k == 1
274+
_edge_case(h[1], h[2], δ[1], δ[2])
275+
elseif k == lastindex(t)
276+
_edge_case(h[end], h[end - 1], δ[end], δ[end - 1])
277+
else
278+
zero(eltype(δ))
279+
end
262280
end
263281
end
264282

0 commit comments

Comments
 (0)