B-Spline use

Hi everyone,

I am having troubling using the BSpline function from NGSolve.
Running with a simple test case with the function i want to interpolate being of the form f(x) = cos(2x). I find with this code (duplicating initial and end points)

Npoints=10
x_lin = np.linspace(np.pi,2np.pi,Npoints)
y=myfun(x_lin)
plt.figure()
x_out=np.linspace(np.pi,2
np.pi,1000)

orders = [1,2,3]
plt.plot(x_out,myfun(x_out),label=“Data”)
for order in orders:
xs=
ys=
# Duplicate start and end points according to degree

xs=xs+[x_lin[0]]
ys=ys+[y[0]]
    
xs=xs+x_lin.tolist()    
ys=ys+y.tolist()

xs=xs+[x_lin[Npoints-1]]
ys=ys+[y[Npoints-1]]

print(xs,ys)
x_list=xs
y_list=ys


spline = BSpline(order,  x_list, y_list)

simple_spline.pdf (11.4 KB)

Where there seems to be a slight shift of x values associated with higher orders.
I did look around the forums and there was a suggestion to duplicate the initial and end points according to the order, which I’ve done for orders 1,2,3 below

x_lin = np.linspace(np.pi,2*np.pi,Npoints)
y=myfun(x_lin)

plt.figure()
x_out=np.linspace(np.pi,2*np.pi,1000)

plt.plot(x_out,myfun(x_out),label=“Data”)
for Order in [1,2,3]:
xs=
ys=
# Duplicate start and end points according to degree

xs=xs+[x_lin[0]]
ys=ys+[y[0]]
if Order>=2:
    ys=ys+[y[0]]
    xs=xs+[x_lin[0]]
if Order==3:
    ys=ys+[y[0]]
    xs=xs+[x_lin[0]]

    
xs=xs+x_lin.tolist()    
ys=ys+y.tolist()

xs=xs+[x_lin[Npoints-1]]
ys=ys+[y[Npoints-1]]
if Order>=2:
    ys=ys+[y[Npoints-1]]
    xs=xs+[x_lin[Npoints-1]]
if Order==3:
    ys=ys+[y[Npoints-1]]
    xs=xs+[x_lin[Npoints-1]]

print(xs,ys)
x_list=xs
y_list=ys


spline = BSpline(Order,  x_list, y_list)

but I still yield the same result
simple_spline_padded_order.pdf (11.2 KB)

Is there something I am possibly missing with how I am meant to setup the control points for the problem? or is there maybe a bug with the function.

Any help is appreciated, thanks!

Hello Sayed98,

I recently worked with NGSolve’s BSplines and encountered the same issue. After some trial and error, I found a straightforward workaround:

I first used SciPy to generate a B-Spline and then passed its arguments to NGSolve’s BSpline. Attention should be paid as the order of the scipy spline is not the same as for the BSpline (order 1 = constant, order 2 = linear,…).

import numpy as np
import scipy.interpolate as si
import matplotlib.pyplot as plt
from ngsolve import BSpline

# Define data points
x = np.linspace(0, 1, 10)
y = np.sin(2 * np.pi * x)  # Example function

# Create a B-Spline with SciPy
degree = 3  # Cubic spline
tck = si.splrep(x, y, k=degree)  # Get knots, coefficients, and degree

# Extract SciPy spline parameters
knots = tck[0]  # Knot vector
vals = tck[1]   # Control points (called "vals" in NGSolve)
order = tck[2] + 1 # Spline order corrected by 1

# Pass the extracted parameters to an NGSolve BSpline
ngspline = BSpline(order, list(knots), list(vals))

# Create finer x-values for plotting
x_fine = np.linspace(0, 1, 300)

# Evaluate the SciPy spline
y_scipy = si.splev(x_fine, tck)

# Evaluate the NGSolve BSpline
y_ngsolve = [ngspline(xi) for xi in x_fine]

# Plot the results
plt.figure(figsize=(8, 6))
plt.plot(x_fine, y_scipy, label='SciPy B-Spline', linestyle='-', color='blue')
plt.plot(x_fine, y_ngsolve, label='NGSolve B-Spline', linestyle='--', color='red')
plt.scatter(x, y, label="Data Points", color='black', s=30)
plt.xlabel("x")
plt.ylabel("y")
plt.legend()
plt.grid(True)
plt.show()

SciPy should automatically create the correct knot vector.

I hope this helps!