From 230f55aa21911a61f3856e8a1081690a452c7c9f Mon Sep 17 00:00:00 2001 From: Neil Wu <602725+nwu63@users.noreply.github.com> Date: Fri, 21 May 2021 18:01:54 -0400 Subject: [PATCH] Fix import issues and restore backwards compatibility (#25) --- examples/example_curve.py | 10 +- examples/example_surf.py | 6 +- examples/example_volume.py | 4 +- pyspline/pyCurve.py | 8 +- pyspline/pySpline.py | 151 +++---------------------------- pyspline/utils.py | 142 +++++++++++++++++++++++++++++ tests/reg_tests/test_curves.py | 12 +-- tests/reg_tests/test_surfaces.py | 6 +- tests/reg_tests/test_volumes.py | 6 +- 9 files changed, 181 insertions(+), 164 deletions(-) diff --git a/examples/example_curve.py b/examples/example_curve.py index 204b39d..89395f6 100644 --- a/examples/example_curve.py +++ b/examples/example_curve.py @@ -5,7 +5,7 @@ import numpy as np # First party modules -from pyspline import pySpline +from pyspline import Curve # Get some Helix-like data @@ -15,13 +15,13 @@ y = np.sin(theta) z = np.linspace(0, 1, n) print("Helix Data") -curve = pySpline.Curve(x=x, y=y, z=z, k=4, Nctl=16, niter=100) +curve = Curve(x=x, y=y, z=z, k=4, Nctl=16, niter=100) curve.writeTecplot("helix.dat") # Load naca0012 data print("Naca 0012 data") x, y = np.loadtxt("naca0012", unpack=True) -curve = pySpline.Curve(x=x, y=y, k=4, Nctl=11, niter=500) +curve = Curve(x=x, y=y, k=4, Nctl=11, niter=500) curve.writeTecplot("naca_data.dat") # Projection Tests @@ -29,7 +29,7 @@ x = [0, 2, 3, 5] y = [-2, 5, 3, 0] z = [0, 0, 0, 0] -curve1 = pySpline.Curve(x=x, y=y, z=z, k=4) +curve1 = Curve(x=x, y=y, z=z, k=4) curve1.writeTecplot("curve1.dat") @@ -37,7 +37,7 @@ y = [5, 1, 4, 2] z = [3, 0, 1, 4] -curve2 = pySpline.Curve(x=x, y=y, z=z, k=4) +curve2 = Curve(x=x, y=y, z=z, k=4) curve2.writeTecplot("curve2.dat") # Get the minimum distance distance between a point and each curve diff --git a/examples/example_surf.py b/examples/example_surf.py index 1ca96b0..583445f 100644 --- a/examples/example_surf.py +++ b/examples/example_surf.py @@ -4,7 +4,7 @@ import numpy as np # First party modules -from pyspline import pySpline +from pyspline import Curve, Surface # Create a generic surface nu = 20 @@ -13,7 +13,7 @@ v = np.linspace(0, 4, nv) [V, U] = np.meshgrid(v, u) Z = np.cos(U) * np.sin(V) -surf = pySpline.Surface(x=U, y=V, z=Z, ku=4, kv=4, Nctlu=5, Nctlv=5) +surf = Surface(x=U, y=V, z=Z, ku=4, kv=4, Nctlu=5, Nctlv=5) surf.writeTecplot("surface.dat") n = 100 @@ -21,7 +21,7 @@ x = np.cos(theta) - 1 y = np.sin(theta) + 1 z = np.linspace(0, 1, n) + 2 -curve = pySpline.Curve(x=x, y=y, z=z, k=4, Nctl=16, niter=100) +curve = Curve(x=x, y=y, z=z, k=4, Nctl=16, niter=100) curve.writeTecplot("helix.dat") u, v, s, D = surf.projectCurve(curve, Niter=100, eps1=1e-10, eps2=1e-10, u=1, v=1, s=1) diff --git a/examples/example_volume.py b/examples/example_volume.py index ad14014..5d7af17 100644 --- a/examples/example_volume.py +++ b/examples/example_volume.py @@ -6,7 +6,7 @@ import numpy as np # First party modules -from pyspline import pySpline +from pyspline import Volume X = np.zeros((2, 2, 2, 3)) X[0, 0, 0, :] = [0, 0, 0] @@ -19,7 +19,7 @@ X[1, 1, 1, :] = [1.2, 1.0, 2] X[0, 1, 1, :] = [-0.2, 1.3, 2.1] -vol = pySpline.Volume(X=X, ku=2, kv=2, kw=2, Nctlu=2, Nctlv=2, Nctlw=2) +vol = Volume(X=X, ku=2, kv=2, kw=2, Nctlu=2, Nctlv=2, Nctlw=2) vol.writeTecplot("vol.dat", orig=True) # Generate random data diff --git a/pyspline/pyCurve.py b/pyspline/pyCurve.py index fb6cc18..0ed4e24 100644 --- a/pyspline/pyCurve.py +++ b/pyspline/pyCurve.py @@ -76,13 +76,13 @@ class Curve(object): >>> y = [0, 0.25, 1.0] >>> s = [0., 0.5, 1.0] >>> # Spatial interpolated seg - >>> line_seg = pySpline.Curve(x=x, y=y, k=2) + >>> line_seg = Curve(x=x, y=y, k=2) >>> # With explicit parameter values - >>> line_seg = pySpline.Curve(x=x, y=y, k=2, s=s) + >>> line_seg = Curve(x=x, y=y, k=2, s=s) >>> #LMS parabolic curve - >>> parabola = pySpline.Curve(x=x, y=y, k=3) + >>> parabola = Curve(x=x, y=y, k=3) >>> #LMS parabolic curve with parameter values - >>> parabola = pySpline.Curve(x=x, y=y, k=3, s=s) + >>> parabola = Curve(x=x, y=y, k=3, s=s) """ def __init__(self, **kwargs): diff --git a/pyspline/pySpline.py b/pyspline/pySpline.py index 719982c..1d299f4 100644 --- a/pyspline/pySpline.py +++ b/pyspline/pySpline.py @@ -6,142 +6,19 @@ :class:`Volume` """ -# External modules -import numpy as np - # Local modules from . import libspline # noqa: F401 -from .pyCurve import Curve -from .pySurface import Surface -from .pyVolume import Volume -from .utils import Error - -# ---------------------------------------------------------------------- -# Misc Helper Functions -# ---------------------------------------------------------------------- - - -def trilinearVolume(*args): - """This is a short-cut function to create a trilinear b-spline - volume. It can be created with ``x`` **OR** with ``xmin`` and - ``xmax``. - - Parameters - ---------- - x : array of size (2, 2, 2, 3) - Coordinates of the corners of the box. - - xmin : array of size (3) - The extreme lower corner of the box - xmax : array of size (3) - The extreme upper corner of the box. In this case, by - construction, the box will be coordinate axis aligned. - """ - tu = [0, 0, 1, 1] - tv = [0, 0, 1, 1] - tw = [0, 0, 1, 1] - ku = 2 - kv = 2 - kw = 2 - - if len(args) == 1: - return Volume(coef=args[0], tu=tu, tv=tv, tw=tw, ku=ku, kv=kv, kw=kw) - elif len(args) == 2: - xmin = np.array(args[0]).astype("d") - xmax = np.array(args[1]).astype("d") - - xLow = xmin[0] - xHigh = xmax[0] - yLow = xmin[1] - yHigh = xmax[1] - zLow = xmin[2] - zHigh = xmax[2] - - coef = np.zeros((2, 2, 2, 3)) - coef[0, 0, 0, :] = [xLow, yLow, zLow] - coef[1, 0, 0, :] = [xHigh, yLow, zLow] - coef[0, 1, 0, :] = [xLow, yHigh, zLow] - coef[1, 1, 0, :] = [xHigh, yHigh, zLow] - coef[0, 0, 1, :] = [xLow, yLow, zHigh] - coef[1, 0, 1, :] = [xHigh, yLow, zHigh] - coef[0, 1, 1, :] = [xLow, yHigh, zHigh] - coef[1, 1, 1, :] = [xHigh, yHigh, zHigh] - - return Volume(coef=coef, tu=tu, tv=tv, tw=tw, ku=ku, kv=kv, kw=kw) - else: - raise Error("An unknown number of arguments was passed to trilinear Volume") - - -def bilinearSurface(*args): - """This is short-cut function to create a bilinear surface. - - Args can contain: - - 1. ``x`` array of size(4, 3). The four corners of the array - arranged in the coordinate direction orientation:: - - 2 3 - +----------+ - | | - | | - | | - +----------+ - 0 1 - - 2. ``p1``, ``p2``, ``p3``, ``p4``. Individual corner points in CCW Ordering:: - - 3 2 - +----------+ - | | - | | - | | - +----------+ - 0 1 - """ - if len(args) == 1: - # One argument passed in ... assume its X - if len(args[0]) != 4: - raise Error("A single argument passed to bilinear surface must contain 4 points and be of size (4, 3)") - coef = np.zeros((2, 2, 3)) - coef[0, 0] = args[0][0] - coef[1, 0] = args[0][1] - coef[0, 1] = args[0][2] - coef[1, 1] = args[0][3] - return Surface(coef=coef, tu=[0, 0, 1, 1], tv=[0, 0, 1, 1], ku=2, kv=2) - else: - # Assume 4 arguments - coef = np.zeros([2, 2, 3]) - coef[0, 0] = args[0] - coef[1, 0] = args[1] - coef[0, 1] = args[3] - coef[1, 1] = args[2] - return Surface(coef=coef, tu=[0, 0, 1, 1], tv=[0, 0, 1, 1], ku=2, kv=2) - - -def line(*args, **kwargs): - """This is a short cut function to create a line as a pySpline Curve object. - - Args can contain: (pick one) - - 1. ``X`` array of size(2, ndim). The two end points - 2. ``x1``, ``x2`` The two end points (each of size ndim) - 3. ``x```, dir=direction. A point and a displacement vector - 4. ``x1``, dir=direction, length=length. As 3. but with a specific length - """ - - if len(args) == 2: - # Its a two-point type - return Curve(coef=[args[0], args[1]], k=2, t=[0, 0, 1, 1]) - elif len(args) == 1: - if len(args[0]) == 2: # its X - return Curve(coef=args[0], k=2, t=[0, 0, 1, 1]) - elif "dir" in kwargs: - # We have point and direction - if "length" in kwargs: - x2 = args[0] + kwargs["dir"] / np.linalg.norm(kwargs["dir"]) * kwargs["length"] - else: - x2 = args[0] + kwargs["dir"] - - return Curve(coef=[args[0], x2], k=2, t=[0, 0, 1, 1]) - else: - Error("Error: dir must be specified if only 1 argument is given") +from .pyCurve import Curve # noqa: F401 +from .pySurface import Surface # noqa: F401 +from .pyVolume import Volume # noqa: F401 +from .utils import ( # noqa: F401 + bilinearSurface, + checkInput, + closeTecplot, + line, + openTecplot, + trilinearVolume, + writeTecplot1D, + writeTecplot2D, + writeTecplot3D, +) diff --git a/pyspline/utils.py b/pyspline/utils.py index c660090..c08b0f4 100644 --- a/pyspline/utils.py +++ b/pyspline/utils.py @@ -1,3 +1,11 @@ +""" +pySpline +-------- + +Contains classes for working with B-spline :class:`Curve`, :class:`Surface` and +:class:`Volume` +""" + # External modules import numpy as np from scipy import sparse @@ -211,3 +219,137 @@ def checkInput(inputVal, inputName, dataType, dataRank, dataShape=None): return tmp.squeeze() else: return tmp + + +def trilinearVolume(*args): + """This is a short-cut function to create a trilinear b-spline + volume. It can be created with ``x`` **OR** with ``xmin`` and + ``xmax``. + + Parameters + ---------- + x : array of size (2, 2, 2, 3) + Coordinates of the corners of the box. + + xmin : array of size (3) + The extreme lower corner of the box + xmax : array of size (3) + The extreme upper corner of the box. In this case, by + construction, the box will be coordinate axis aligned. + """ + # Local modules + from .pyVolume import Volume + + tu = [0, 0, 1, 1] + tv = [0, 0, 1, 1] + tw = [0, 0, 1, 1] + ku = 2 + kv = 2 + kw = 2 + + if len(args) == 1: + return Volume(coef=args[0], tu=tu, tv=tv, tw=tw, ku=ku, kv=kv, kw=kw) + elif len(args) == 2: + xmin = np.array(args[0]).astype("d") + xmax = np.array(args[1]).astype("d") + + xLow = xmin[0] + xHigh = xmax[0] + yLow = xmin[1] + yHigh = xmax[1] + zLow = xmin[2] + zHigh = xmax[2] + + coef = np.zeros((2, 2, 2, 3)) + coef[0, 0, 0, :] = [xLow, yLow, zLow] + coef[1, 0, 0, :] = [xHigh, yLow, zLow] + coef[0, 1, 0, :] = [xLow, yHigh, zLow] + coef[1, 1, 0, :] = [xHigh, yHigh, zLow] + coef[0, 0, 1, :] = [xLow, yLow, zHigh] + coef[1, 0, 1, :] = [xHigh, yLow, zHigh] + coef[0, 1, 1, :] = [xLow, yHigh, zHigh] + coef[1, 1, 1, :] = [xHigh, yHigh, zHigh] + + return Volume(coef=coef, tu=tu, tv=tv, tw=tw, ku=ku, kv=kv, kw=kw) + else: + raise Error("An unknown number of arguments was passed to trilinear Volume") + + +def bilinearSurface(*args): + """This is short-cut function to create a bilinear surface. + + Args can contain: + + 1. ``x`` array of size(4, 3). The four corners of the array + arranged in the coordinate direction orientation:: + + 2 3 + +----------+ + | | + | | + | | + +----------+ + 0 1 + + 2. ``p1``, ``p2``, ``p3``, ``p4``. Individual corner points in CCW Ordering:: + + 3 2 + +----------+ + | | + | | + | | + +----------+ + 0 1 + """ + # Local modules + from .pySurface import Surface + + if len(args) == 1: + # One argument passed in ... assume its X + if len(args[0]) != 4: + raise Error("A single argument passed to bilinear surface must contain 4 points and be of size (4, 3)") + coef = np.zeros((2, 2, 3)) + coef[0, 0] = args[0][0] + coef[1, 0] = args[0][1] + coef[0, 1] = args[0][2] + coef[1, 1] = args[0][3] + return Surface(coef=coef, tu=[0, 0, 1, 1], tv=[0, 0, 1, 1], ku=2, kv=2) + else: + # Assume 4 arguments + coef = np.zeros([2, 2, 3]) + coef[0, 0] = args[0] + coef[1, 0] = args[1] + coef[0, 1] = args[3] + coef[1, 1] = args[2] + return Surface(coef=coef, tu=[0, 0, 1, 1], tv=[0, 0, 1, 1], ku=2, kv=2) + + +def line(*args, **kwargs): + """This is a short cut function to create a line as a pySpline Curve object. + + Args can contain: (pick one) + + 1. ``X`` array of size(2, ndim). The two end points + 2. ``x1``, ``x2`` The two end points (each of size ndim) + 3. ``x```, dir=direction. A point and a displacement vector + 4. ``x1``, dir=direction, length=length. As 3. but with a specific length + """ + # Local modules + from .pyCurve import Curve + + if len(args) == 2: + # Its a two-point type + return Curve(coef=[args[0], args[1]], k=2, t=[0, 0, 1, 1]) + elif len(args) == 1: + if len(args[0]) == 2: # its X + return Curve(coef=args[0], k=2, t=[0, 0, 1, 1]) + elif "dir" in kwargs: + # We have point and direction + if "length" in kwargs: + x2 = args[0] + kwargs["dir"] / np.linalg.norm(kwargs["dir"]) * kwargs["length"] + else: + x2 = args[0] + kwargs["dir"] + + return Curve(coef=[args[0], x2], k=2, t=[0, 0, 1, 1]) + else: + Error("Error: dir must be specified if only 1 argument is given") diff --git a/tests/reg_tests/test_curves.py b/tests/reg_tests/test_curves.py index 4760f50..b65f144 100644 --- a/tests/reg_tests/test_curves.py +++ b/tests/reg_tests/test_curves.py @@ -8,7 +8,7 @@ from numpy.testing import assert_allclose # First party modules -from pyspline import pySpline +from pyspline import Curve baseDir = os.path.dirname(os.path.abspath(__file__)) @@ -108,7 +108,7 @@ def regression_test(self, handler): coef[0] = [0, 0.6] coef[1] = [1.1, 1.4] coef[2] = [2.6, 5.1] - curve = pySpline.Curve(t=t, k=k, coef=coef) + curve = Curve(t=t, k=k, coef=coef) run_curve_test(curve, handler, "2D k={}".format(k)) io_test(curve) @@ -120,7 +120,7 @@ def regression_test(self, handler): coef[1] = [0.71, 1.5] coef[2] = [2.5, 5.9] coef[3] = [4, -2] - curve = pySpline.Curve(t=t, k=k, coef=coef) + curve = Curve(t=t, k=k, coef=coef) run_curve_test(curve, handler, "2D k={}".format(k)) io_test(curve) @@ -133,7 +133,7 @@ def regression_test(self, handler): coef[2] = [1.6, 5.2] coef[3] = [4.2, -2.24] coef[4] = [2.9, 6.2] - curve = pySpline.Curve(t=t, k=k, coef=coef) + curve = Curve(t=t, k=k, coef=coef) run_curve_test(curve, handler, "2D k={}".format(k)) io_test(curve) @@ -150,7 +150,7 @@ def regression_test(self, handler): for k in [2, 3, 4]: test_name = "LMS test k={}".format(k) # print('--------- Test helix data with k=%d-------'%(k)) - curve = pySpline.Curve(x=x, y=y, z=z, k=k, nCtl=16, niter=50) + curve = Curve(x=x, y=y, z=z, k=k, nCtl=16, niter=50) run_curve_test(curve, handler, test_name) run_project_test(curve, handler, test_name) @@ -160,6 +160,6 @@ def regression_test(self, handler): for k in [2, 3, 4]: test_name = "interpolation test k={}".format(k) # print('--------- Test helix data with k=%d-------'%(k)) - curve = pySpline.Curve(x=x, y=y, z=z, k=k) + curve = Curve(x=x, y=y, z=z, k=k) run_curve_test(curve, handler, test_name) run_project_test(curve, handler, test_name) diff --git a/tests/reg_tests/test_surfaces.py b/tests/reg_tests/test_surfaces.py index aa0428e..40780e5 100644 --- a/tests/reg_tests/test_surfaces.py +++ b/tests/reg_tests/test_surfaces.py @@ -8,7 +8,7 @@ from numpy.testing import assert_allclose # First party modules -from pyspline import pySpline +from pyspline import Curve, Surface baseDir = os.path.dirname(os.path.abspath(__file__)) @@ -115,7 +115,7 @@ def run_project_test(surface, handler, test_name): y = [4, 3, 2, 1] z = [-3, 1, 3, 5] - curve = pySpline.Curve(k=kc, x=x, y=y, z=z) + curve = Curve(k=kc, x=x, y=y, z=z) u, v, s, D = surface.projectCurve(curve) # ---------- surface-curve projection with kc = kc handler.root_add_val("{} projected curve u with kc={}".format(test_name, kc), u, tol=eps) @@ -168,7 +168,7 @@ def regression_test(self, handler, solve=False): for nCtlu in [5, 10]: for nCtlv in [5, 10]: test_name = "surface with ku={}, kv={}, nCtlu={}, nCtlv={}".format(ku, kv, nCtlu, nCtlv) - surface = pySpline.Surface(x=U, y=V, z=Z, ku=ku, kv=kv, nCtlu=nCtlu, nCtlv=nCtlv) + surface = Surface(x=U, y=V, z=Z, ku=ku, kv=kv, nCtlu=nCtlu, nCtlv=nCtlv) surface.recompute() run_surface_test(surface, handler, test_name) run_project_test(surface, handler, test_name) diff --git a/tests/reg_tests/test_volumes.py b/tests/reg_tests/test_volumes.py index 200379d..b2bf105 100644 --- a/tests/reg_tests/test_volumes.py +++ b/tests/reg_tests/test_volumes.py @@ -7,7 +7,7 @@ import numpy as np # First party modules -from pyspline import pySpline +from pyspline import Volume baseDir = os.path.dirname(os.path.abspath(__file__)) @@ -2187,9 +2187,7 @@ def regression_test(self, handler, solve=False): test_name = "volume with ku={}, kv={}, kw={}, nCtlu={}, nCtlv={}, nCtlw={}".format( ku, kv, kw, nCtlu, nCtlv, nCtlw ) - volume = pySpline.Volume( - X=X, ku=ku, kv=kv, kw=kw, nCtlu=nCtlu, nCtlv=nCtlv, nCtlw=nCtlw - ) + volume = Volume(X=X, ku=ku, kv=kv, kw=kw, nCtlu=nCtlu, nCtlv=nCtlv, nCtlw=nCtlw) volume.recompute() run_volume_test(volume, handler, test_name) run_project_test(volume, handler, test_name)