-
Notifications
You must be signed in to change notification settings - Fork 119
Description
I am trying to build splines with discontinuities by increasing the multiplicity of the knot at the discontinuity. My understanding is that this can be achieved through splinter's support for custom knots; namely, using the two-step procedure described in #76 and #72.
However, as soon as I move away from using the bspline_interpolator() builder to building the spline from parameters using BSpline.from_param(), I get oscillations (as illustrated below).
Oscillations occur, even when I don't introduce knot multiplicity in the interior of the knot vector, i.e. when just trying to replicate bspline_interpolator() using BSpline.from_param():
import numpy as np
import matplotlib.pyplot as plt
import sys, os
import splinterpy
# splinterpy.load( PATH_HERE )
def g(x):
if x <= 0.5:
return 1
else:
return np.exp(-10*(x - 0.5))
gridsize = 51
grid = np.linspace(0, 1, gridsize)
# Define knots
knots = np.sort(np.append(grid, [0, 0, 0, 1, 1, 1]))
# Sample from function
y_data = np.zeros(gridsize)
for x_index, x in enumerate(grid):
y_data[x_index] = g(x)
# Build splines
# Using bspline_interpolator
builder_spline = splinterpy.bspline_interpolator(grid, y_data, degree=3)
# Using BSpline.from_param
degrees = 3
knots = knots.tolist()
dim_y = 1
spline = splinterpy.BSpline.from_param(degrees, knots, dim_y)
fitted_spline = spline.fit(grid, y_data)
# Evaluate splines at fine grid
fine_grid = np.linspace(0, 1, 1001)
builder_spline_eval = builder_spline.eval(fine_grid)
fitted_spline_eval = fitted_spline.eval(fine_grid)Examining the knots of the two splines shows that they differ in that bspline_interpolator() has "removed" the second and second-to-last elements (0.02 and 0.98, respectively):
print(builder_spline.get_knot_vectors())
# [[0.0, 0.0, 0.0, 0.0, 0.04, 0.06000000000000001, 0.08, 0.1, 0.12, 0.13999999999999999, 0.16, 0.18, 0.2, 0.22000000000000003, 0.24000000000000005, 0.26, 0.28, 0.30000000000000004, 0.32, 0.33999999999999997, 0.36, 0.38, 0.4, 0.42000000000000004, 0.44000000000000006, 0.45999999999999996, 0.48, 0.5, 0.52, 0.54, 0.56, 0.5800000000000001, 0.6000000000000001, 0.62, 0.64, 0.66, 0.68, 0.7, 0.72, 0.74, 0.76, 0.78, 0.8, 0.8200000000000001, 0.8400000000000001, 0.86, 0.8800000000000001, 0.9, 0.9199999999999999, 0.9400000000000001, 0.9600000000000002, 1.0, 1.0, 1.0, 1.0]]
print(fitted_spline.get_knot_vectors())
# [[0.0, 0.0, 0.0, 0.0, 0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26, 0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.42, 0.44, 0.46, 0.48, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6, 0.62, 0.64, 0.66, 0.68, 0.7000000000000001, 0.72, 0.74, 0.76, 0.78, 0.8, 0.8200000000000001, 0.84, 0.86, 0.88, 0.9, 0.92, 0.9400000000000001, 0.96, 0.98, 1.0, 1.0, 1.0, 1.0]]Removing these two elements from the knot vector fed into BSpline.from_param() makes the two splines identical:
knots = np.sort(np.append(grid, [0, 0, 0, 1, 1, 1]))
knots = knots[(knots != 0.02) & (knots != 0.98)]Introducing multiple knots at the discontinuity (0.5) leads to oscillations around the discontinuity...
knots = np.sort(np.append(grid, [0, 0, 0, 0.5, 0.5, 1, 1, 1]))
knots = knots[(knots != 0.02) & (knots != 0.98)]... unless the knots surrounding the discontinuity (0.48 and 0.52) are removed:
knots = np.sort(np.append(grid, [0, 0, 0, 0.5, 0.5, 1, 1, 1]))
knots = knots[(knots != 0.02) & (knots != 0.98)]
knots = knots[(knots != 0.48) & (knots != 0.52)]I think I am missing something about knot placement. Why do knots surrounding knot multiplicities need to be "removed" in order to avoid oscillations?



