tataratat / splinepy

Library for prototyping spline geometries of arbitrary dimensions and degrees, and IGA
https://tataratat.github.io/splinepy
Other
45 stars 13 forks source link

Fixes multidimensional bug, requires at least numpy version 1.7.0 #420

Closed jzwar closed 4 months ago

jzwar commented 4 months ago

See title

Should work now, tests run

Checklists

j042 commented 4 months ago

thanks! do you have any idea why this happens? this is the surface fit for examples/fitting.py here, we get a different value for u_k compare to the one from the nurbs book / our previous implementation. Screenshot 2024-04-19 at 18 54 10

jzwar commented 4 months ago

I ran the example but cannot seem to reproduce the error

image

@j042

j042 commented 4 months ago

take a look at the one with [18, 15]

jzwar commented 4 months ago

Pretty sure there is a bug in the geomdl parametrisation


from geomdl import fitting
from splinepy import cartesian_product
import numpy as np
from splinepy.helpme.fit import parameterize

n_fitting_points = [5, 6]
centripetal = False
angle = 45

solution = [np.linspace(0, 1, a)**(i+1)
            for i, a in enumerate(n_fitting_points)]
fitting_points = cartesian_product(
    solution
)

sp_param = parameterize(fitting_points, n_fitting_points, centripetal)
geom_param = fitting.compute_params_surface(
    fitting_points, *n_fitting_points, centripetal)
print(f"Splinepy Implementation: {np.allclose(solution[0].ravel(), sp_param[0].ravel())}"
      f" {np.allclose(solution[1].ravel(), sp_param[1].ravel())}")
print(f"GeomMDL Implementation: {np.allclose(solution[0].ravel(), geom_param[0])}"
      f" {np.allclose(solution[1].ravel(), geom_param[1])}")
FSchwar commented 4 months ago

That's certainly some strange behaviour. I tried several different combinations and as far as I understand, the issue occurs only if n_cpts[0] is slightly less than n_sample[0]. The issue occurs e.g. for n_sample=[20, 20] for n_cpts[0]>17.

image

or for n_sample=[30, 30] for the cases n_cpts[0]>26, while the "oscillatory" behaviour at the end gets worse.

image

Here we can also see the issue for n_sample=[15,15] where a slight creek starts building up for n_cpts=[13,13], which then results again in an oscillation for n_cpts=[14,14].

image

For the second axis, this is never the case. The approximation is stable for all different variations of n_cpts[1].

I then tried the same with simple curve_fitting, and also found the same instabilities:

image

jzwar commented 4 months ago

If it also happens for curves then the parametrization cannot be the issue. The line code produces the same results. Maybe there is an issue with knot-vector computations

jzwar commented 4 months ago

@j042 have you compared the knotvwctors with geomdl by chance ?

@FSchwar can you post a minimum example for a line that fails? Maybe with a smaller number of ctps so we can easily identify the issue

j042 commented 4 months ago

We can probably check against scipy too. I will check

j042 commented 4 months ago

Don't see the difference in compute_knot_vector . also with the nurbs book

jzwar commented 4 months ago

Then the curve example should also fail with geomdl, right?

FSchwar commented 4 months ago

This would be an example for the issue shown in curve fitting (as shown above)

import gustaf as gus
import numpy as np
import splinepy

def f(x):
    return x**4 - 2 * x**2 + x + 0.2 * np.sin(10 * x)

n_sample = 25
n_resolution = 3 * n_sample
x = np.linspace(-1, 1, n_sample)
fitting_points = np.vstack([x, f(x)]).T.reshape(-1, 2)
pts = gus.create.vertices.Vertices(fitting_points)
pts.show_options["c"] = "blue"
pts.show_options["r"] = 10

interpolated_curve, _ = splinepy.helpme.fit.curve(
    fitting_points=fitting_points, degree=2
)

gus_list = [[
        "Interpolated curve",
        interpolated_curve,
        pts,
    ]]

for n_cps in [24, 22, 15]:

    approximated_curve, _ = splinepy.helpme.fit.curve(
        fitting_points=fitting_points, degree=3, n_control_points=n_cps
    )
    gus_list.append([
            f"Approximated curve with {n_cps} CPs",
            approximated_curve,
            pts,
        ])

gus.show(*gus_list)
j042 commented 4 months ago

Here's a pattern - if you try to fit n queries with n - degree control points, such fitting happens. anyone aware of some rule we are breaking here? (of course, it's also possible that we may have implemented something differently)

FSchwar commented 4 months ago

I thought so too at first - but for the curve fitting example we have degree=3 and the start of the strange behaviour can be clearly seen until n_cps=15 if you zoom in, even though n_sample-degree=22:

image

jzwar commented 4 months ago

Then the curve example should also fail with geomdl, right?

@j042 ?

j042 commented 4 months ago

yes