def test_axis(ST, quad, axis): kwargs = {} if not ST.family() == 'fourier': kwargs['quad'] = quad ST = ST(N, **kwargs) points, weights = ST.points_and_weights(N) f_hat = shenfun.Function(ST) f_hat[:] = np.random.random(f_hat.shape[0]) B = inner_product((ST, 0), (ST, 0)) c = shenfun.Function(ST) c = B.solve(f_hat, c) # Multidimensional version f0 = shenfun.Array(ST) bc = [np.newaxis,]*3 bc[axis] = slice(None) ST.tensorproductspace = ABC(3, ST.coors) ST.plan((N,)*3, axis, f0.dtype, {}) if ST.has_nonhomogeneous_bcs: ST.bc.set_tensor_bcs(ST, ST) # To set Dirichlet boundary conditions on multidimensional array ck = shenfun.Function(ST) fk = np.broadcast_to(f_hat[tuple(bc)], ck.shape).copy() ck = B.solve(fk, ck, axis=axis) cc = [1,]*3 cc[axis] = slice(None) assert np.allclose(ck[tuple(cc)], c, rtol=1e-5, atol=1e-6)
def test_helmholtz2D(family, axis): la = lla if family == 'chebyshev': la = cla N = (8, 9) SD = shenfun.Basis(N[axis], family=family, bc=(0, 0)) K1 = shenfun.Basis(N[(axis + 1) % 2], family='F', dtype='d') subcomms = mpi4py_fft.pencil.Subcomm(MPI.COMM_WORLD, allaxes2D[axis]) bases = [K1] bases.insert(axis, SD) T = shenfun.TensorProductSpace(subcomms, bases, axes=allaxes2D[axis]) u = shenfun.TrialFunction(T) v = shenfun.TestFunction(T) if family == 'chebyshev': mat = shenfun.inner(v, shenfun.div(shenfun.grad(u))) else: mat = shenfun.inner(shenfun.grad(v), shenfun.grad(u)) H = la.Helmholtz(*mat) H = la.Helmholtz(*mat) u = shenfun.Function(T) u[:] = np.random.random(u.shape) + 1j * np.random.random(u.shape) f = shenfun.Function(T) f = H.matvec(u, f) f = H.matvec(u, f) g0 = shenfun.Function(T) g1 = shenfun.Function(T) M = {d.get_key(): d for d in mat} g0 = M['ADDmat'].matvec(u, g0) g1 = M['BDDmat'].matvec(u, g1) assert np.linalg.norm(f - (g0 + g1)) < 1e-12, np.linalg.norm(f - (g0 + g1))
def test_convolve(basis, N): """Test convolution""" FFT = basis(N) u0 = shenfun.Function(FFT) u1 = shenfun.Function(FFT) M = u0.shape[0] u0[:] = np.random.rand(M) + 1j*np.random.rand(M) u1[:] = np.random.rand(M) + 1j*np.random.rand(M) if isinstance(FFT, fbases.R2C): # Make sure spectral data corresponds to real input u0[0] = u0[0].real u1[0] = u1[0].real if N % 2 == 0: u0[-1] = u0[-1].real u1[-1] = u1[-1].real uv1 = FFT.convolve(u0, u1, fast=False) # Do convolution with FFT and padding FFT2 = basis(N, padding_factor=(1.5+1.00001/N)) # Just enough to be perfect uv2 = FFT2.convolve(u0, u1, fast=True) # Compare. Should be identical after truncation if no aliasing uv3 = np.zeros_like(uv2) if isinstance(FFT, fbases.R2C): uv3[:] = uv1[:N//2+1] if N % 2 == 0: uv3[-1] *= 2 uv3[-1] = uv3[-1].real else: uv3[:N//2+1] = uv1[:N//2+1] uv3[-(N//2):] += uv1[-(N//2):] assert np.allclose(uv3, uv2)
def test_axis(ST, quad, axis): kwargs = {'plan': True} if not ST.family() == 'fourier': kwargs['quad'] = quad ST = ST(N, **kwargs) points, weights = ST.points_and_weights(N) f_hat = shenfun.Function(ST) f_hat[:] = np.random.random(f_hat.shape[0]) B = inner_product((ST, 0), (ST, 0)) c = shenfun.Function(ST) c = B.solve(f_hat, c) # Multidimensional version f0 = shenfun.Array(ST) bc = [ np.newaxis, ] * 3 bc[axis] = slice(None) ST.plan((N, ) * 3, axis, f0.dtype, {}) if hasattr(ST, 'bc'): ST.bc.set_tensor_bcs( ST ) # To set Dirichlet boundary conditions on multidimensional array ck = shenfun.Function(ST) fk = np.broadcast_to(f_hat[bc], ck.shape).copy() ck = B.solve(fk, ck, axis=axis) cc = [ 0, ] * 3 cc[axis] = slice(None) assert np.allclose(ck[cc], c)
def test_CDDmat(quad): M = 128 SD = cbases.ShenDirichletBasis(M, quad=quad) u = (1 - x**2) * sin(np.pi * 6 * x) dudx = u.diff(x, 1) points, weights = SD.points_and_weights(M) ul = lambdify(x, u, 'numpy') dudx_l = lambdify(x, dudx, 'numpy') dudx_j = dudx_l(points) uj = ul(points) u_hat = shenfun.Function(SD) u_hat = SD.forward(uj, u_hat) uj = SD.backward(u_hat, uj) u_hat = SD.forward(uj, u_hat) uc_hat = shenfun.Function(SD) uc_hat = SD.CT.forward(uj, uc_hat) dudx_j = SD.CT.fast_derivative(uj) Cm = inner_product((SD, 0), (SD, 1)) B = inner_product((SD, 0), (SD, 0)) TDMASolver = TDMA(B) cs = np.zeros_like(u_hat) cs = Cm.matvec(u_hat, cs) # Should equal (but not exact so use extra resolution) cs2 = np.zeros(M) cs2 = SD.scalar_product(dudx_j, cs2) s = SD.slice() assert np.allclose(cs[s], cs2[s]) cs = TDMASolver(cs) du = np.zeros(M) du = SD.backward(cs, du) assert np.linalg.norm(du[s] - dudx_j[s]) / M < 1e-10 # Multidimensional version u3_hat = u_hat.repeat(4 * 4).reshape( (M, 4, 4)) + 1j * u_hat.repeat(4 * 4).reshape((M, 4, 4)) cs = np.zeros_like(u3_hat) cs = Cm.matvec(u3_hat, cs) cs2 = np.zeros((M, 4, 4), dtype=np.complex) du3 = dudx_j.repeat(4 * 4).reshape( (M, 4, 4)) + 1j * dudx_j.repeat(4 * 4).reshape((M, 4, 4)) SD.plan((M, 4, 4), 0, np.complex, {}) cs2 = SD.scalar_product(du3, cs2) assert np.allclose(cs[s], cs2[s], 1e-10) cs = TDMASolver(cs) d3 = np.zeros((M, 4, 4), dtype=np.complex) d3 = SD.backward(cs, d3) assert np.linalg.norm(du3[s] - d3[s]) / (M * 16) < 1e-10
def test_scalarproduct(ST, quad): """Test fast scalar product against Vandermonde computed version""" kwargs = {} if not ST.family() == 'fourier': kwargs['quad'] = quad ST = ST(N, **kwargs) f = x*x+cos(pi*x) fj = shenfun.Array(ST, buffer=f) u0 = shenfun.Function(ST) u1 = shenfun.Function(ST) u0 = ST.scalar_product(fj, u0, fast_transform=True) u1 = ST.scalar_product(fj, u1, fast_transform=False) assert np.allclose(u1, u0) assert not np.all(u1 == u0) # Check that fast is not the same as slow
def test_transforms(ST, quad, dim): kwargs = {} if not ST.family() == 'fourier': kwargs['quad'] = quad ST0 = ST(N, **kwargs) fj = shenfun.Array(ST0) fj[:] = np.random.random(fj.shape[0]) # Project function to space first f_hat = shenfun.Function(ST0) f_hat = ST0.forward(fj, f_hat) fj = ST0.backward(f_hat, fj) # Then check if transformations work as they should u0 = shenfun.Function(ST0) u1 = shenfun.Array(ST0) u0 = ST0.forward(fj, u0) u1 = ST0.backward(u0, u1) assert np.allclose(fj, u1, rtol=1e-5, atol=1e-6) u0 = ST0.forward(fj, u0) u1 = ST0.backward(u0, u1) assert np.allclose(fj, u1, rtol=1e-5, atol=1e-6) u0 = ST0.forward(fj, u0, fast_transform=False) u1 = ST0.backward(u0, u1, fast_transform=False) assert np.allclose(fj, u1, rtol=1e-5, atol=1e-6) # Multidimensional version for axis in range(dim): bc = [ np.newaxis, ] * dim bc[axis] = slice(None) fij = np.broadcast_to(fj[tuple(bc)], (N, ) * dim).copy() ST1 = ST(N, **kwargs) ST1.tensorproductspace = ABC(dim, ST0.coors) ST1.plan((N, ) * dim, axis, fij.dtype, {}) u00 = shenfun.Function(ST1) u11 = shenfun.Array(ST1) u00 = ST1.forward(fij, u00) u11 = ST1.backward(u00, u11) cc = [ 0, ] * dim cc[axis] = slice(None) cc = tuple(cc) assert np.allclose(fij[cc], u11[cc], rtol=1e-5, atol=1e-6) del ST1
def test_scalarproduct(ST, quad): """Test fast scalar product against Vandermonde computed version""" kwargs = {'plan': True} if not ST.family() == 'fourier': kwargs['quad'] = quad ST = ST(N, **kwargs) points, weights = ST.points_and_weights(N) f = x * x + cos(pi * x) fl = lambdify(x, f, 'numpy') fj = fl(points) u0 = shenfun.Function(ST) u1 = shenfun.Function(ST) u0 = ST.scalar_product(fj, u0, fast_transform=True) u1 = ST.scalar_product(fj, u1, fast_transform=False) assert np.allclose(u1, u0) assert not np.all(u1 == u0) # Check that fast is not the same as slow
def test_to_ortho(basis, quad): N = 10 if basis.family() == 'legendre': B1 = lBasis[0](N, quad) #B3 = lBasis[0](N, quad) elif basis.family() == 'chebyshev': if basis.short_name() == 'DU': B1 = cBasisGC[0](N, quad) else: B1 = cBasis[0](N, quad) #B3 = cBasis[0](N, quad) elif basis.family() == 'laguerre': B1 = laBasis[0](N, quad) #B3 = laBasis[0](N, quad) B0 = basis(N, quad=quad) a = shenfun.Array(B0) a_hat = shenfun.Function(B0) b0_hat = shenfun.Function(B1) b1_hat = shenfun.Function(B1) a[:] = np.random.random(a.shape) a_hat = a.forward(a_hat) b0_hat = shenfun.project(a_hat, B1, output_array=b0_hat, fill=False, use_to_ortho=True) b1_hat = shenfun.project(a_hat, B1, output_array=b1_hat, fill=False, use_to_ortho=False) assert np.linalg.norm(b0_hat-b1_hat) < 1e-10 #B2 = basis(N, quad=quad) TD = shenfun.TensorProductSpace(shenfun.comm, (B0, B0)) TC = shenfun.TensorProductSpace(shenfun.comm, (B1, B1)) a = shenfun.Array(TD) a_hat = shenfun.Function(TD) b0_hat = shenfun.Function(TC) b1_hat = shenfun.Function(TC) a[:] = np.random.random(a.shape) a_hat = a.forward(a_hat) b0_hat = shenfun.project(a_hat, TC, output_array=b0_hat, fill=False, use_to_ortho=True) b1_hat = shenfun.project(a_hat, TC, output_array=b1_hat, fill=False, use_to_ortho=False) assert np.linalg.norm(b0_hat-b1_hat) < 1e-10 F0 = shenfun.FunctionSpace(N, 'F') TD = shenfun.TensorProductSpace(shenfun.comm, (B0, F0)) TC = shenfun.TensorProductSpace(shenfun.comm, (B1, F0)) a = shenfun.Array(TD) a_hat = shenfun.Function(TD) b0_hat = shenfun.Function(TC) b1_hat = shenfun.Function(TC) a[:] = np.random.random(a.shape) a_hat = a.forward(a_hat) b0_hat = shenfun.project(a_hat, TC, output_array=b0_hat, fill=False, use_to_ortho=True) b1_hat = shenfun.project(a_hat, TC, output_array=b1_hat, fill=False, use_to_ortho=False) assert np.linalg.norm(b0_hat-b1_hat) < 1e-10
def test_project_1D(basis): ue = sin(2*np.pi*x)*(1-x**2) T = basis(12) u = shenfun.TrialFunction(T) v = shenfun.TestFunction(T) u_tilde = shenfun.Function(T) X = T.mesh() ua = shenfun.Array(T, buffer=ue) u_tilde = shenfun.inner(v, ua, output_array=u_tilde) M = shenfun.inner(u, v) u_p = shenfun.Function(T) u_p = M.solve(u_tilde, u=u_p) u_0 = shenfun.Function(T) u_0 = shenfun.project(ua, T) assert np.allclose(u_0, u_p) u_1 = shenfun.project(ue, T) assert np.allclose(u_1, u_p)
def test_transforms(ST, quad, axis): kwargs = {'plan': True} if not ST.family() == 'fourier': kwargs['quad'] = quad ST = ST(N, **kwargs) points, weights = ST.points_and_weights(N) fj = shenfun.Array(ST) fj[:] = np.random.random(fj.shape[0]) # Project function to space first f_hat = shenfun.Function(ST) f_hat = ST.forward(fj, f_hat) fj = ST.backward(f_hat, fj) # Then check if transformations work as they should u0 = shenfun.Function(ST) u1 = shenfun.Array(ST) u0 = ST.forward(fj, u0) u1 = ST.backward(u0, u1) assert np.allclose(fj, u1) u0 = ST.forward(fj, u0) u1 = ST.backward(u0, u1) assert np.allclose(fj, u1) # Multidimensional version bc = [ np.newaxis, ] * 3 bc[axis] = slice(None) fj = np.broadcast_to(fj[bc], (N, ) * 3).copy() ST.plan((N, ) * 3, axis, fj.dtype, {}) if hasattr(ST, 'bc'): ST.bc.set_slices(ST) # To set Dirichlet boundary conditions u00 = shenfun.Function(ST) u11 = shenfun.Array(ST) u00 = ST.forward(fj, u00) u11 = ST.backward(u00, u11) cc = [ 0, ] * 3 cc[axis] = slice(None) assert np.allclose(fj[cc], u11[cc])
def test_biharmonic3D(family, axis): la = lla if family == 'chebyshev': la = cla N = (16, 16, 16) SD = shenfun.Basis(N[allaxes3D[axis][0]], family=family, bc='Biharmonic') K1 = shenfun.Basis(N[allaxes3D[axis][1]], family='F', dtype='D') K2 = shenfun.Basis(N[allaxes3D[axis][2]], family='F', dtype='d') subcomms = mpi4py_fft.pencil.Subcomm(MPI.COMM_WORLD, [0, 1, 1]) bases = [0] * 3 bases[allaxes3D[axis][0]] = SD bases[allaxes3D[axis][1]] = K1 bases[allaxes3D[axis][2]] = K2 T = shenfun.TensorProductSpace(subcomms, bases, axes=allaxes3D[axis]) u = shenfun.TrialFunction(T) v = shenfun.TestFunction(T) if family == 'chebyshev': mat = shenfun.inner( v, shenfun.div(shenfun.grad(shenfun.div(shenfun.grad(u))))) else: mat = shenfun.inner(shenfun.div(shenfun.grad(v)), shenfun.div(shenfun.grad(u))) H = la.Biharmonic(*mat) H = la.Biharmonic(*mat) u = shenfun.Function(T) u[:] = np.random.random(u.shape) + 1j * np.random.random(u.shape) f = shenfun.Function(T) f = H.matvec(u, f) f = H.matvec(u, f) g0 = shenfun.Function(T) g1 = shenfun.Function(T) g2 = shenfun.Function(T) M = {d.get_key(): d for d in mat} amat = 'ABBmat' if family == 'chebyshev' else 'PBBmat' g0 = M['SBBmat'].matvec(u, g0) g1 = M[amat].matvec(u, g1) g2 = M['BBBmat'].matvec(u, g2) assert np.linalg.norm(f - (g0 + g1 + g2)) < 1e-8, np.linalg.norm(f - (g0 + g1 + g2))
def test_div2(basis, quad): B = basis(8, quad=quad, plan=True) u = shenfun.TrialFunction(B) v = shenfun.TestFunction(B) m = shenfun.inner(u, v) z = shenfun.Function(B, val=1) c = m / z m2 = m.diags('csr') c2 = spsolve(m2, z[B.slice()]) assert np.allclose(c2, c[B.slice()])
def test_CDDmat(quad): M = 48 SD = cbases.ShenDirichlet(M, quad=quad) u = (1-x**2)*sin(np.pi*6*x) dudx = u.diff(x, 1) dudx_hat = shenfun.Function(SD, buffer=dudx) u_hat = shenfun.Function(SD, buffer=u) ducdx_hat = shenfun.project(shenfun.Dx(u_hat, 0, 1), SD) assert np.linalg.norm(ducdx_hat-dudx_hat)/M < 1e-10, np.linalg.norm(ducdx_hat-dudx_hat)/M # Multidimensional version SD0 = cbases.ShenDirichlet(8, quad=quad) SD1 = cbases.ShenDirichlet(M, quad=quad) T = shenfun.TensorProductSpace(shenfun.comm, (SD0, SD1)) u = (1-y**2)*sin(np.pi*6*y) dudy = u.diff(y, 1) dudy_hat = shenfun.Function(T, buffer=dudy) u_hat = shenfun.Function(T, buffer=u) ducdy_hat = shenfun.project(shenfun.Dx(u_hat, 1, 1), T) assert np.linalg.norm(ducdy_hat-dudy_hat)/M < 1e-10, np.linalg.norm(ducdy_hat-dudy_hat)/M
def test_mul2(): mat = shenfun.SparseMatrix({0: 1}, (3, 3)) v = np.ones(3) c = mat * v assert np.allclose(c, 1) mat = shenfun.SparseMatrix({-2:1, -1:1, 0: 1, 1:1, 2:1}, (3, 3)) c = mat * v assert np.allclose(c, 3) SD = shenfun.Basis(8, "L", bc=(0, 0), plan=True, scaled=True) u = shenfun.TrialFunction(SD) v = shenfun.TestFunction(SD) mat = shenfun.inner(shenfun.grad(u), shenfun.grad(v)) z = shenfun.Function(SD, val=1) c = mat * z assert np.allclose(c[:6], 1)
def get_dimensional_solution(self): assert hasattr(self, "_solution") vec_space = list() for i in range(self._dim): tens_space = [] for j in range(self._dim): basis = sf.FunctionSpace(self._N[j], family='legendre', bc=self._bcs[i][j], domain=tuple(self._domain[j])) tens_space.append(basis) vec_space.append(sf.TensorProductSpace(sf.comm, tuple(tens_space))) V = sf.VectorSpace(vec_space) u_hat = sf.Function(V) for i in range(self._dim): # u has the same expansions coefficients as u_dimless u_hat[i] = self._u_ref * self._solution[i] return u_hat
def test_transforms(ST, quad): N = 10 kwargs = {} if not ST.family() == 'fourier': kwargs['quad'] = quad ST0 = ST(N, **kwargs) fj = shenfun.Array(ST0) fj[:] = np.random.random(N) fj = fj.forward().backward().copy() assert np.allclose(fj, fj.forward().backward()) u0 = shenfun.Function(ST0) u1 = shenfun.Array(ST0) u0 = ST0.forward(fj, u0, fast_transform=False) u1 = ST0.backward(u0, u1, fast_transform=False) assert np.allclose(fj, u1, rtol=1e-5, atol=1e-6) # Multidimensional version ST0 = ST(N, **kwargs) if ST0.short_name() in ('R2C', 'C2C'): F0 = shenfun.FunctionSpace(N, 'F', dtype='D') T0 = shenfun.TensorProductSpace(shenfun.comm, (F0, ST0)) else: F0 = shenfun.FunctionSpace(N, 'F', dtype='d') T0 = shenfun.TensorProductSpace(shenfun.comm, (F0, ST0)) fij = shenfun.Array(T0) fij[:] = np.random.random(T0.shape(False)) fij = fij.forward().backward().copy() assert np.allclose(fij, fij.forward().backward()) if ST0.short_name() in ('R2C', 'C2C'): F0 = shenfun.FunctionSpace(N, 'F', dtype='D') F1 = shenfun.FunctionSpace(N, 'F', dtype='D') T = shenfun.TensorProductSpace(shenfun.comm, (F0, F1, ST0), dtype=ST0.dtype.char) else: F0 = shenfun.FunctionSpace(N, 'F', dtype='d') F1 = shenfun.FunctionSpace(N, ST.family()) T = shenfun.TensorProductSpace(shenfun.comm, (F0, ST0, F1)) fij = shenfun.Array(T) fij[:] = np.random.random(T.shape(False)) fij = fij.forward().backward().copy() assert np.allclose(fij, fij.forward().backward())
def test_eval(ST, quad): """Test eval against fast inverse""" kwargs = {} if not ST.family() == 'fourier': kwargs['quad'] = quad ST = ST(N, **kwargs) points, weights = ST.mpmath_points_and_weights(N) fk = shenfun.Function(ST) fj = shenfun.Array(ST) fj[:] = np.random.random(fj.shape[0]) fk = ST.forward(fj, fk) fj = ST.backward(fk, fj) fk = ST.forward(fj, fk) f = ST.eval(points, fk) assert np.allclose(fj, f, rtol=1e-5, atol=1e-6), np.linalg.norm(fj-f) fj = ST.backward(fk, fj, fast_transform=False) fk = ST.forward(fj, fk, fast_transform=False) f = ST.eval(points, fk) assert np.allclose(fj, f, rtol=1e-5, atol=1e-6)
def test_eval(ST, quad): """Test eval agains fast inverse""" kwargs = {} if not ST.family() == 'fourier': kwargs['quad'] = quad ST = ST(N, **kwargs) points, weights = ST.points_and_weights(N) fk = shenfun.Function(ST) fj = shenfun.Array(ST) fj[:] = np.random.random(fj.shape[0]) fk = ST.forward(fj, fk) fj = ST.backward(fk, fj) fk = ST.forward(fj, fk) f = ST.eval(points, fk) #from IPython import embed; embed() assert np.allclose(fj, f) fj = ST.backward(fk, fj, fast_transform=False) fk = ST.forward(fj, fk, fast_transform=False) f = ST.eval(points, fk) assert np.allclose(fj, f)
def __call__(self, a_hat, b_hat, ab_hat=None): """Compute convolution of a_hat and b_hat without truncation Parameters ---------- a_hat : Function b_hat : Function ab_hat : Function """ Tp = self.padding_space T = self.newspace if ab_hat is None: ab_hat = shenfun.Function(T) a = shenfun.Array(Tp) b = shenfun.Array(Tp) a = Tp.backward(a_hat, a) b = Tp.backward(b_hat, b) ab_hat = T.forward(a * b, ab_hat) return ab_hat
def test_neg(basis): e = shenfun.Expr(basis) e2 = -e assert np.allclose(np.array(e.scales()).astype(np.int), (-np.array(e2.scales())).astype(np.int)) K0 = shenfun.FunctionSpace(N, 'F', dtype='D') K1 = shenfun.FunctionSpace(N, 'F', dtype='D') K2 = shenfun.FunctionSpace(N, 'F', dtype='d') K3 = shenfun.FunctionSpace(N, 'C', dtype='d') T = shenfun.TensorProductSpace(comm, (K0, K1, K2)) C = shenfun.TensorProductSpace(comm, (K1, K2, K3)) TT = shenfun.VectorTensorProductSpace(T) CC = shenfun.VectorTensorProductSpace(C) VT = shenfun.MixedTensorProductSpace([TT, T]) KK = shenfun.MixedTensorProductSpace([T, T, C]) vf = shenfun.Function(TT) va = shenfun.Array(TT) cf = shenfun.Function(CC) ca = shenfun.Array(CC) df = shenfun.Function(KK) da = shenfun.Array(KK) @pytest.mark.parametrize('u', (va, vf, cf, ca, df, da)) def test_index(u): va0 = u[0] va1 = u[1] va2 = u[2] assert (va0.index(), va1.index(), va2.index()) == (0, 1, 2) assert va0.function_space() is u.function_space()[0] assert va1.function_space() is u.function_space()[1] assert va2.function_space() is u.function_space()[2]
import shenfun as sf import numpy as np import sympy as sp import matplotlib.pyplot as plt N = 10 L = sf.FunctionSpace(N, family='legendre', bc=(0, 0)) print(L.__class__) # plot quadrature points quad_points = L.mpmath_points_and_weights()[0] plt.scatter(quad_points, np.zeros_like(quad_points)) # a projection x = sp.symbols('x', real=True) f = 1 - 1 / 2 * (3 * x**2 - 1) # the first Shen-Dirichlet basis function P = sf.Function(L) func = sf.project(f, L) func_quad = sf.Array(L, buffer=f) plt.scatter(quad_points, func_quad) # should be orthogonal to all others except 0th and 2nd scalprod = L.scalar_product(func_quad) assert np.allclose(scalprod[np.r_[1, 3:N - 1]], 0) assert np.logical_not(np.allclose(scalprod[np.r_[0, 2]], 0))