class ShenDirichletBasis(ChebyshevBase): """Shen basis for Dirichlet boundary conditions Parameters ---------- N : int, optional Number of quadrature points quad : str, optional Type of quadrature - GL - Chebyshev-Gauss-Lobatto - GC - Chebyshev-Gauss bc : 2-tuple of floats, optional Boundary conditions at x=(1,-1). For Poisson eq. plan : bool, optional Plan transforms on __init__ or not. If basis is part of a TensorProductSpace, then planning needs to be delayed. domain : 2-tuple of floats, optional The computational domain scaled : bool, optional Whether or not to use scaled basis """ def __init__(self, N=0, quad="GC", bc=(0, 0), plan=False, domain=(-1., 1.), scaled=False): ChebyshevBase.__init__(self, N, quad, domain=domain) from shenfun.tensorproductspace import BoundaryValues self.CT = Basis(N, quad, plan=plan) self._scaled = scaled self._factor = np.ones(1) if plan: self.plan(N, 0, np.float, {}) self.bc = BoundaryValues(self, bc=bc) def get_vandermonde_basis(self, V): P = np.zeros(V.shape) P[:, :-2] = V[:, :-2] - V[:, 2:] P[:, -2] = (V[:, 0] + V[:, 1])/2 P[:, -1] = (V[:, 0] - V[:, 1])/2 return P def is_scaled(self): """Return True if scaled basis is used, otherwise False""" return False def evaluate_scalar_product(self, input_array, output_array, fast_transform=True): if fast_transform is False: self.vandermonde_scalar_product(input_array, output_array) return output = self.CT.scalar_product(fast_transform=fast_transform) s0 = self.sl(0) s1 = self.sl(1) c0 = 0.5*(output[s0] + output[s1]) c1 = 0.5*(output[s0] - output[s1]) s0[self.axis] = slice(0, -2) s1[self.axis] = slice(2, None) output[s0] -= output[s1] s0[self.axis] = -2 output[s0] = c0 s0[self.axis] = -1 output[s0] = c1 def evaluate_expansion_all(self, input_array, output_array, fast_transform=True): if fast_transform is False: SpectralBase.evaluate_expansion_all(self, input_array, output_array, False) return w_hat = work[(input_array, 0)] s0 = self.sl(slice(0, -2)) s1 = self.sl(slice(2, None)) w_hat[s0] = input_array[s0] w_hat[s1] -= input_array[s0] self.bc.apply_before(w_hat, False, (0.5, 0.5)) self.CT.backward(w_hat) assert output_array is self.CT.backward.output_array def slice(self): return slice(0, self.N-2) def eval(self, x, fk, output_array=None): if output_array is None: output_array = np.zeros(x.shape) x = self.map_reference_domain(x) w_hat = work[(fk, 0)] output_array[:] = n_cheb.chebval(x, fk[:-2]) w_hat[2:] = fk[:-2] output_array -= n_cheb.chebval(x, w_hat) output_array += 0.5*(fk[-1]*(1+x)+fk[-2]*(1-x)) return output_array def plan(self, shape, axis, dtype, options): if isinstance(axis, tuple): axis = axis[0] if isinstance(self.forward, Transform): if self.forward.input_array.shape == shape and self.axis == axis: # Already planned return self.CT.plan(shape, axis, dtype, options) self.axis = self.CT.axis xfftn_fwd = self.CT.forward.xfftn xfftn_bck = self.CT.backward.xfftn U = xfftn_fwd.input_array V = xfftn_fwd.output_array self.forward = Transform(self.forward, xfftn_fwd, U, V, V) self.backward = Transform(self.backward, xfftn_bck, V, V, U) self.scalar_product = Transform(self.scalar_product, xfftn_fwd, U, V, V)
class ShenDirichletBasis(ChebyshevBase): """Shen basis for Dirichlet boundary conditions Parameters ---------- N : int, optional Number of quadrature points quad : str, optional Type of quadrature - GL - Chebyshev-Gauss-Lobatto - GC - Chebyshev-Gauss bc : 2-tuple of floats, optional Boundary conditions at x=(1,-1). For Poisson eq. domain : 2-tuple of floats, optional The computational domain scaled : bool, optional Whether or not to use scaled basis """ def __init__(self, N=0, quad="GC", bc=(0, 0), domain=(-1., 1.), scaled=False): ChebyshevBase.__init__(self, N, quad, domain=domain) from shenfun.tensorproductspace import BoundaryValues self.CT = Basis(N, quad) self._scaled = scaled self._factor = np.ones(1) self.plan(N, 0, np.float, {}) self.bc = BoundaryValues(self, bc=bc) @staticmethod def boundary_condition(): return 'Dirichlet' def _composite_basis(self, V): P = np.zeros(V.shape) P[:, :-2] = V[:, :-2] - V[:, 2:] P[:, -2] = (V[:, 0] + V[:, 1])/2 P[:, -1] = (V[:, 0] - V[:, 1])/2 return P def sympy_basis(self, i=0): x = sympy.symbols('x') return sympy.chebyshevt(i, x) - sympy.chebyshevt(i+2, x) def evaluate_basis(self, x, i=0, output_array=None): x = np.atleast_1d(x) if output_array is None: output_array = np.zeros(x.shape) if i < self.N-2: w = np.arccos(x) output_array[:] = np.cos(i*w) - np.cos((i+2)*w) elif i == self.N-2: output_array[:] = 0.5*(1+x) elif i == self.N-1: output_array[:] = 0.5*(1-x) return output_array def is_scaled(self): """Return True if scaled basis is used, otherwise False""" return False def evaluate_scalar_product(self, input_array, output_array, fast_transform=True): if fast_transform is False: self.vandermonde_scalar_product(input_array, output_array) return output = self.CT.scalar_product(fast_transform=fast_transform) s0 = self.si[0] s1 = self.si[1] c0 = 0.5*(output[s0] + output[s1]) c1 = 0.5*(output[s0] - output[s1]) s0 = self.sl[slice(0, -2)] s1 = self.sl[slice(2, None)] output[s0] -= output[s1] output[self.si[-2]] = c0 output[self.si[-1]] = c1 def evaluate_expansion_all(self, input_array, output_array, fast_transform=True): if fast_transform is False: SpectralBase.evaluate_expansion_all(self, input_array, output_array, False) return w_hat = work[(input_array, 0, True)] s0 = self.sl[slice(0, -2)] s1 = self.sl[slice(2, None)] w_hat[s0] = input_array[s0] w_hat[s1] -= input_array[s0] self.bc.apply_before(w_hat, False, (0.5, 0.5)) self.CT.backward(w_hat) assert output_array is self.CT.backward.output_array def slice(self): return slice(0, self.N-2) def eval(self, x, u, output_array=None): if output_array is None: output_array = np.zeros(x.shape) x = self.map_reference_domain(x) w_hat = work[(u, 0, True)] output_array[:] = n_cheb.chebval(x, u[:-2]) w_hat[2:] = u[:-2] output_array -= n_cheb.chebval(x, w_hat) output_array += 0.5*(u[-1]*(1-x)+u[-2]*(1+x)) return output_array def plan(self, shape, axis, dtype, options): if isinstance(axis, tuple): assert len(axis) == 1 axis = axis[-1] if isinstance(self.forward, Transform): if self.forward.input_array.shape == shape and self.axis == axis: # Already planned return self.CT.plan(shape, axis, dtype, options) self.CT.tensorproductspace = self.tensorproductspace xfftn_fwd = self.CT.forward.xfftn xfftn_bck = self.CT.backward.xfftn U = xfftn_fwd.input_array V = xfftn_fwd.output_array self.axis = axis self.forward = Transform(self.forward, xfftn_fwd, U, V, V) self.backward = Transform(self.backward, xfftn_bck, V, V, U) self.scalar_product = Transform(self.scalar_product, xfftn_fwd, U, V, V) self.si = islicedict(axis=self.axis, dimensions=self.dimensions()) self.sl = slicedict(axis=self.axis, dimensions=self.dimensions())