def warp_factor(n, output_nodes, scaled=True): """Compute warp function at order *n* and evaluate it at the nodes *output_nodes*. """ from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes warped_nodes = legendre_gauss_lobatto_nodes(n) equi_nodes = np.linspace(-1, 1, n+1) from modepy.matrices import vandermonde from modepy.modes import simplex_onb basis = simplex_onb(1, n) Veq = vandermonde(basis, equi_nodes) # noqa # create interpolator from equi_nodes to output_nodes eq_to_out = la.solve(Veq.T, vandermonde(basis, output_nodes).T).T # compute warp factor warp = np.dot(eq_to_out, warped_nodes - equi_nodes) if scaled: zerof = (abs(output_nodes) < 1.0-1.0e-10) sf = 1.0 - (zerof*output_nodes)**2 warp = warp/sf + warp*(zerof-1) return warp
def warp_factor(n, output_nodes, scaled=True): """Compute warp function at order *n* and evaluate it at the nodes *output_nodes*. """ from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes warped_nodes = legendre_gauss_lobatto_nodes(n) equi_nodes = np.linspace(-1, 1, n + 1) from modepy.matrices import vandermonde from modepy.modes import simplex_onb basis = simplex_onb(1, n) Veq = vandermonde(basis, equi_nodes) # noqa # create interpolator from equi_nodes to output_nodes eq_to_out = la.solve(Veq.T, vandermonde(basis, output_nodes).T).T # compute warp factor warp = np.dot(eq_to_out, warped_nodes - equi_nodes) if scaled: zerof = (abs(output_nodes) < 1.0 - 1.0e-10) sf = 1.0 - (zerof * output_nodes)**2 warp = warp / sf + warp * (zerof - 1) return warp
def __init__(self, mesh_el_group, order, index): from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes unit_nodes_1d = legendre_gauss_lobatto_nodes(order) unit_nodes = mp.tensor_product_nodes([unit_nodes_1d] * mesh_el_group.dim) super().__init__(mesh_el_group, order, index, unit_nodes=unit_nodes)
def warp_and_blend_nodes(dims, n, node_tuples=None): """Return interpolation nodes as described in [warburton-nodes]_ .. [warburton-nodes] Warburton, T. "An Explicit Construction of Interpolation Nodes on the Simplex." Journal of Engineering Mathematics 56, no. 3 (2006): 247-262. http://dx.doi.org/10.1007/s10665-006-9086-6 :arg dims: dimensionality of desired simplex (1, 2 or 3, i.e. interval, triangle or tetrahedron). :arg n: Desired maximum total polynomial degree to interpolate. :arg node_tuples: a list of tuples of integers indicating the node order. Use default order if *None*, see :func:`pytools.generate_nonnegative_integer_tuples_summing_to_at_most`. :returns: An array of shape *(dims, nnodes)* containing unit coordinates of the interpolation nodes. (see :ref:`tri-coords` and :ref:`tet-coords`) The generated nodes have benign `Lebesgue constants <https://en.wikipedia.org/wiki/Lebesgue_constant_(interpolation)>`_. (See also :func:`modepy.tools.estimate_lebesgue_constant`) """ if dims == 0: return np.empty((0, 1), dtype=np.float64) elif dims == 1: from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes result = legendre_gauss_lobatto_nodes(n) if node_tuples is not None: new_result = np.empty_like(result) if len(node_tuples) != n + 1: raise ValueError( "node_tuples list does not have the correct length") for i, (nti, ) in enumerate(node_tuples): new_result[i] = result[nti] result = new_result return result.reshape(1, -1) elif dims == 2: return warp_and_blend_nodes_2d(n, node_tuples) elif dims == 3: return warp_and_blend_nodes_3d(n, node_tuples) else: raise NotImplementedError("%d-dimensional node sets" % dims)
def warp_and_blend_nodes(dims, n, node_tuples=None): """Return interpolation nodes as described in [warburton-nodes]_ .. [warburton-nodes] Warburton, T. "An Explicit Construction of Interpolation Nodes on the Simplex." Journal of Engineering Mathematics 56, no. 3 (2006): 247-262. http://dx.doi.org/10.1007/s10665-006-9086-6 :arg dims: dimensionality of desired simplex (1, 2 or 3, i.e. interval, triangle or tetrahedron). :arg n: Desired maximum total polynomial degree to interpolate. :arg node_tuples: a list of tuples of integers indicating the node order. Use default order if *None*, see :func:`pytools.generate_nonnegative_integer_tuples_summing_to_at_most`. :returns: An array of shape *(dims, nnodes)* containing unit coordinates of the interpolation nodes. (see :ref:`tri-coords` and :ref:`tet-coords`) The generated nodes have benign `Lebesgue constants <https://en.wikipedia.org/wiki/Lebesgue_constant_(interpolation)>`_. (See also :func:`modepy.tools.estimate_lebesgue_constant`) """ if dims == 0: return np.empty((0, 1), dtype=np.float64) elif dims == 1: from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes result = legendre_gauss_lobatto_nodes(n) if node_tuples is not None: new_result = np.empty_like(result) if len(node_tuples) != n+1: raise ValueError("node_tuples list does not have the correct length") for i, (nti,) in enumerate(node_tuples): new_result[i] = result[nti] result = new_result return result.reshape(1, -1) elif dims == 2: return warp_and_blend_nodes_2d(n, node_tuples) elif dims == 3: return warp_and_blend_nodes_3d(n, node_tuples) else: raise NotImplementedError("%d-dimensional node sets" % dims)
def make_group_from_vertices(vertices, vertex_indices, order, group_cls=None, unit_nodes=None, group_factory=None): if group_factory is not None: from warnings import warn warn("'group_factory' is deprecated, use 'group_cls' instead", DeprecationWarning, stacklevel=2) if group_cls is not None: raise ValueError("cannot set both 'group_cls' and 'group_factory'") group_cls = group_factory # shape: (ambient_dim, nelements, nvertices) ambient_dim = vertices.shape[0] el_vertices = vertices[:, vertex_indices] from meshmode.mesh import SimplexElementGroup, TensorProductElementGroup if group_cls is None: group_cls = SimplexElementGroup if issubclass(group_cls, SimplexElementGroup): if order < 1: raise ValueError("can't represent simplices with mesh order < 1") el_origins = el_vertices[:, :, 0][:, :, np.newaxis] # ambient_dim, nelements, nspan_vectors spanning_vectors = (el_vertices[:, :, 1:] - el_origins) nspan_vectors = spanning_vectors.shape[-1] dim = nspan_vectors # dim, nunit_nodes if unit_nodes is None: if dim <= 3: unit_nodes = mp.warp_and_blend_nodes(dim, order) else: unit_nodes = mp.equidistant_nodes(dim, order) unit_nodes_01 = 0.5 + 0.5 * unit_nodes nodes = np.einsum("si,des->dei", unit_nodes_01, spanning_vectors) + el_origins elif issubclass(group_cls, TensorProductElementGroup): nelements, nvertices = vertex_indices.shape dim = nvertices.bit_length() - 1 if nvertices != 2**dim: raise ValueError("invalid number of vertices for tensor-product " "elements, must be power of two") if unit_nodes is None: from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes unit_nodes = mp.tensor_product_nodes( dim, legendre_gauss_lobatto_nodes(order)) # shape: (dim, nnodes) unit_nodes_01 = 0.5 + 0.5 * unit_nodes _, nnodes = unit_nodes.shape from pytools import generate_nonnegative_integer_tuples_below as gnitb id_tuples = list(gnitb(2, dim)) assert len(id_tuples) == nvertices vdm = np.empty((nvertices, nvertices)) for i, vertex_tuple in enumerate(id_tuples): for j, func_tuple in enumerate(id_tuples): vertex_ref = np.array(vertex_tuple, dtype=np.float64) vdm[i, j] = np.prod(vertex_ref**func_tuple) # shape: (ambient_dim, nelements, nvertices) coeffs = np.empty((ambient_dim, nelements, nvertices)) for d in range(ambient_dim): coeffs[d] = la.solve(vdm, el_vertices[d].T).T vdm_nodes = np.zeros((nnodes, nvertices)) for j, func_tuple in enumerate(id_tuples): vdm_nodes[:, j] = np.prod(unit_nodes_01**np.array(func_tuple).reshape( -1, 1), axis=0) nodes = np.einsum("ij,dej->dei", vdm_nodes, coeffs) else: raise ValueError(f"unsupported value for 'group_cls': {group_cls}") # make contiguous nodes = nodes.copy() return group_cls(order, vertex_indices, nodes, unit_nodes=unit_nodes)
def unit_nodes(self): from modepy.nodes import tensor_product_nodes from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes return tensor_product_nodes(self.dim, legendre_gauss_lobatto_nodes(self.order))
def make_group_from_vertices(vertices, vertex_indices, order, group_factory=None): # shape: (dim, nelements, nvertices) el_vertices = vertices[:, vertex_indices] from meshmode.mesh import SimplexElementGroup, TensorProductElementGroup if group_factory is None: group_factory = SimplexElementGroup if issubclass(group_factory, SimplexElementGroup): el_origins = el_vertices[:, :, 0][:, :, np.newaxis] # ambient_dim, nelements, nspan_vectors spanning_vectors = ( el_vertices[:, :, 1:] - el_origins) nspan_vectors = spanning_vectors.shape[-1] dim = nspan_vectors # dim, nunit_nodes if dim <= 3: unit_nodes = mp.warp_and_blend_nodes(dim, order) else: unit_nodes = mp.equidistant_nodes(dim, order) unit_nodes_01 = 0.5 + 0.5*unit_nodes nodes = np.einsum( "si,des->dei", unit_nodes_01, spanning_vectors) + el_origins elif issubclass(group_factory, TensorProductElementGroup): nelements, nvertices = vertex_indices.shape dim = 0 while True: if nvertices == 2**dim: break if nvertices < 2**dim: raise ValueError("invalid number of vertices for tensor-product " "elements, must be power of two") dim += 1 from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes from modepy.nodes import tensor_product_nodes unit_nodes = tensor_product_nodes(dim, legendre_gauss_lobatto_nodes(order)) # shape: (dim, nnodes) unit_nodes_01 = 0.5 + 0.5*unit_nodes _, nnodes = unit_nodes.shape from pytools import generate_nonnegative_integer_tuples_below as gnitb id_tuples = list(gnitb(2, dim)) assert len(id_tuples) == nvertices vdm = np.empty((nvertices, nvertices)) for i, vertex_tuple in enumerate(id_tuples): for j, func_tuple in enumerate(id_tuples): vertex_ref = np.array(vertex_tuple, dtype=np.float64) vdm[i, j] = np.prod(vertex_ref**func_tuple) # shape: (dim, nelements, nvertices) coeffs = np.empty((dim, nelements, nvertices)) for d in range(dim): coeffs[d] = la.solve(vdm, el_vertices[d].T).T vdm_nodes = np.zeros((nnodes, nvertices)) for j, func_tuple in enumerate(id_tuples): vdm_nodes[:, j] = np.prod( unit_nodes_01 ** np.array(func_tuple).reshape(-1, 1), axis=0) nodes = np.einsum("ij,dej->dei", vdm_nodes, coeffs) else: raise ValueError("unsupported value for 'group_factory': %s" % group_factory) # make contiguous nodes = nodes.copy() return group_factory( order, vertex_indices, nodes, unit_nodes=unit_nodes)
def legendre_gauss_lobatto_tensor_product_nodes(dims, n): from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes return tensor_product_nodes(dims, legendre_gauss_lobatto_nodes(n))
def unit_nodes(self): from modepy.nodes import tensor_product_nodes from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes return tensor_product_nodes( self.dim, legendre_gauss_lobatto_nodes(self.order))