예제 #1
0
파일: nodes.py 프로젝트: inducer/modepy
def warp_and_blend_nodes_2d(n, node_tuples=None):
    try:
        alpha = _alpha_opt_2d[n-1]
    except IndexError:
        alpha = 5/3

    if node_tuples is None:
        from pytools import generate_nonnegative_integer_tuples_summing_to_at_most \
                as gnitstam
        node_tuples = list(gnitstam(n, 2))
    else:
        if len(node_tuples) != (n+1)*(n+2)//2:
            raise ValueError("node_tuples list does not have the correct length")

    # shape: (2, nnodes)
    unit_nodes = (np.array(node_tuples, dtype=np.float64)/n*2 - 1).T

    from modepy.tools import (
            unit_to_barycentric,
            barycentric_to_equilateral,
            equilateral_to_unit)
    bary = unit_to_barycentric(unit_nodes)

    return equilateral_to_unit(
        barycentric_to_equilateral(bary)
        + _2d_equilateral_shift(n, bary, alpha))
예제 #2
0
def test_barycentric_coordinate_map(dims):
    from random import Random
    rng = Random(17)

    n = 5
    unit = np.empty((dims, n))
    from modepy.tools import (
            pick_random_simplex_unit_coordinate,
            unit_to_barycentric,
            barycentric_to_unit,
            barycentric_to_equilateral,
            equilateral_to_unit,)

    for i in range(n):
        unit[:, i] = pick_random_simplex_unit_coordinate(rng, dims)

    bary = unit_to_barycentric(unit)
    assert (np.abs(np.sum(bary, axis=0) - 1) < 1e-15).all()
    assert (bary >= 0).all()
    unit2 = barycentric_to_unit(bary)
    assert la.norm(unit-unit2) < 1e-14

    equi = barycentric_to_equilateral(bary)
    unit3 = equilateral_to_unit(equi)
    assert la.norm(unit-unit3) < 1e-14
예제 #3
0
def test_barycentric_coordinate_map(dims):
    from random import Random
    rng = Random(17)

    n = 5
    unit = np.empty((dims, n))
    from modepy.tools import (
            pick_random_simplex_unit_coordinate,
            unit_to_barycentric,
            barycentric_to_unit,
            barycentric_to_equilateral,
            equilateral_to_unit,)

    for i in range(n):
        unit[:, i] = pick_random_simplex_unit_coordinate(rng, dims)

    bary = unit_to_barycentric(unit)
    assert (np.abs(np.sum(bary, axis=0) - 1) < 1e-15).all()
    assert (bary >= 0).all()
    unit2 = barycentric_to_unit(bary)
    assert la.norm(unit-unit2) < 1e-14

    equi = barycentric_to_equilateral(bary)
    unit3 = equilateral_to_unit(equi)
    assert la.norm(unit-unit3) < 1e-14
예제 #4
0
파일: nodes.py 프로젝트: userjjb/DbX
def warp_and_blend_nodes_2d(n, node_tuples=None):
    try:
        alpha = _alpha_opt_2d[n - 1]
    except IndexError:
        alpha = 5 / 3

    if node_tuples is None:
        from pytools import generate_nonnegative_integer_tuples_summing_to_at_most \
                as gnitstam
        node_tuples = list(gnitstam(n, 2))
    else:
        if len(node_tuples) != (n + 1) * (n + 2) // 2:
            raise ValueError(
                "node_tuples list does not have the correct length")

    # shape: (2, nnodes)
    unit_nodes = (np.array(node_tuples, dtype=np.float64) / n * 2 - 1).T

    from modepy.tools import (unit_to_barycentric, barycentric_to_equilateral,
                              equilateral_to_unit)
    bary = unit_to_barycentric(unit_nodes)

    return equilateral_to_unit(
        barycentric_to_equilateral(bary) +
        _2d_equilateral_shift(n, bary, alpha))
예제 #5
0
def get_simplex_element_flip_matrix(order, unit_nodes, permutation=None):
    """
    Generate a resampling matrix that corresponds to a
    permutation of the barycentric coordinates being applied.
    The default permutation is to swap the
    first two barycentric coordinates.

    :param order: The order of the function space on the simplex,
                 (see second argument in
                  :fun:`modepy.simplex_best_available_basis`)
    :param unit_nodes: A np array of unit nodes with shape
                       *(dim, nunit_nodes)*
    :param permutation: Either *None*, or a tuple of shape
                        storing a permutation:
                        the *i*th barycentric coordinate gets mapped to
                        the *permutation[i]*th coordinate.

    :return: A numpy array of shape *(nunit_nodes, nunit_nodes)*
             which, when its transpose is right-applied
             to the matrix of nodes (shaped *(dim, nunit_nodes)*),
             corresponds to the permutation being applied
    """
    from modepy.tools import barycentric_to_unit, unit_to_barycentric

    bary_unit_nodes = unit_to_barycentric(unit_nodes)

    flipped_bary_unit_nodes = bary_unit_nodes.copy()
    if permutation is None:
        flipped_bary_unit_nodes[0, :] = bary_unit_nodes[1, :]
        flipped_bary_unit_nodes[1, :] = bary_unit_nodes[0, :]
    else:
        flipped_bary_unit_nodes[permutation, :] = bary_unit_nodes
    flipped_unit_nodes = barycentric_to_unit(flipped_bary_unit_nodes)

    dim = unit_nodes.shape[0]
    shape = mp.Simplex(dim)
    space = mp.PN(dim, order)
    basis = mp.basis_for_space(space, shape)
    flip_matrix = mp.resampling_matrix(basis.functions, flipped_unit_nodes,
                                       unit_nodes)

    flip_matrix[np.abs(flip_matrix) < 1e-15] = 0

    # Flipping twice should be the identity
    if permutation is None:
        assert la.norm(
            np.dot(flip_matrix, flip_matrix) -
            np.eye(len(flip_matrix))) < 1e-13

    return flip_matrix
예제 #6
0
def flip_simplex_element_group(vertices, grp, grp_flip_flags):
    from modepy.tools import barycentric_to_unit, unit_to_barycentric

    from meshmode.mesh import SimplexElementGroup

    if not isinstance(grp, SimplexElementGroup):
        raise NotImplementedError(
            "flips only supported on "
            "exclusively SimplexElementGroup-based meshes")

    # Swap the first two vertices on elements to be flipped.

    new_vertex_indices = grp.vertex_indices.copy()
    new_vertex_indices[grp_flip_flags, 0] \
            = grp.vertex_indices[grp_flip_flags, 1]
    new_vertex_indices[grp_flip_flags, 1] \
            = grp.vertex_indices[grp_flip_flags, 0]

    # Generate a resampling matrix that corresponds to the
    # first two barycentric coordinates being swapped.

    bary_unit_nodes = unit_to_barycentric(grp.unit_nodes)

    flipped_bary_unit_nodes = bary_unit_nodes.copy()
    flipped_bary_unit_nodes[0, :] = bary_unit_nodes[1, :]
    flipped_bary_unit_nodes[1, :] = bary_unit_nodes[0, :]
    flipped_unit_nodes = barycentric_to_unit(flipped_bary_unit_nodes)

    flip_matrix = mp.resampling_matrix(
        mp.simplex_best_available_basis(grp.dim, grp.order),
        flipped_unit_nodes, grp.unit_nodes)

    flip_matrix[np.abs(flip_matrix) < 1e-15] = 0

    # Flipping twice should be the identity
    assert la.norm(
        np.dot(flip_matrix, flip_matrix) - np.eye(len(flip_matrix))) < 1e-13

    # Apply the flip matrix to the nodes.
    new_nodes = grp.nodes.copy()
    new_nodes[:, grp_flip_flags] = np.einsum("ij,dej->dei", flip_matrix,
                                             grp.nodes[:, grp_flip_flags])

    return SimplexElementGroup(grp.order,
                               new_vertex_indices,
                               new_nodes,
                               unit_nodes=grp.unit_nodes)
예제 #7
0
def flip_simplex_element_group(vertices, grp, grp_flip_flags):
    from modepy.tools import barycentric_to_unit, unit_to_barycentric

    from meshmode.mesh import SimplexElementGroup

    if not isinstance(grp, SimplexElementGroup):
        raise NotImplementedError("flips only supported on "
                "exclusively SimplexElementGroup-based meshes")

    # Swap the first two vertices on elements to be flipped.

    new_vertex_indices = grp.vertex_indices.copy()
    new_vertex_indices[grp_flip_flags, 0] \
            = grp.vertex_indices[grp_flip_flags, 1]
    new_vertex_indices[grp_flip_flags, 1] \
            = grp.vertex_indices[grp_flip_flags, 0]

    # Generate a resampling matrix that corresponds to the
    # first two barycentric coordinates being swapped.

    bary_unit_nodes = unit_to_barycentric(grp.unit_nodes)

    flipped_bary_unit_nodes = bary_unit_nodes.copy()
    flipped_bary_unit_nodes[0, :] = bary_unit_nodes[1, :]
    flipped_bary_unit_nodes[1, :] = bary_unit_nodes[0, :]
    flipped_unit_nodes = barycentric_to_unit(flipped_bary_unit_nodes)

    flip_matrix = mp.resampling_matrix(
            mp.simplex_best_available_basis(grp.dim, grp.order),
            flipped_unit_nodes, grp.unit_nodes)

    flip_matrix[np.abs(flip_matrix) < 1e-15] = 0

    # Flipping twice should be the identity
    assert la.norm(
            np.dot(flip_matrix, flip_matrix)
            - np.eye(len(flip_matrix))) < 1e-13

    # Apply the flip matrix to the nodes.
    new_nodes = grp.nodes.copy()
    new_nodes[:, grp_flip_flags] = np.einsum(
            "ij,dej->dei",
            flip_matrix, grp.nodes[:, grp_flip_flags])

    return SimplexElementGroup(
            grp.order, new_vertex_indices, new_nodes,
            unit_nodes=grp.unit_nodes)
예제 #8
0
    def flip_matrix(self):
        """
            :return: The matrix which should be applied to the
                     *(dim, nunitnodes)*-shaped array of nodes corresponding to
                     an element in order to change orientation - <-> +.

                     The matrix will be *(dim, dim)* and orthogonal with
                     *np.float64* type entries.
        """
        if self._flip_matrix is None:
            # This is very similar to :mod:`meshmode` in processing.py
            # the function :function:`from_simplex_element_group`, but
            # we needed to use firedrake nodes

            from modepy.tools import barycentric_to_unit, unit_to_barycentric

            # Generate a resampling matrix that corresponds to the
            # first two barycentric coordinates being swapped.

            bary_unit_nodes = unit_to_barycentric(self.unit_nodes())

            flipped_bary_unit_nodes = bary_unit_nodes.copy()
            flipped_bary_unit_nodes[0, :] = bary_unit_nodes[1, :]
            flipped_bary_unit_nodes[1, :] = bary_unit_nodes[0, :]
            flipped_unit_nodes = barycentric_to_unit(flipped_bary_unit_nodes)

            from modepy import resampling_matrix, simplex_best_available_basis

            flip_matrix = resampling_matrix(
                simplex_best_available_basis(self.dim(),
                                             self.analog().degree),
                flipped_unit_nodes, self.unit_nodes())

            flip_matrix[np.abs(flip_matrix) < 1e-15] = 0

            # Flipping twice should be the identity
            assert la.norm(
                np.dot(flip_matrix, flip_matrix) -
                np.eye(len(flip_matrix))) < 1e-13

            self._flip_matrix = flip_matrix

        return self._flip_matrix
예제 #9
0
def test_barycentric_coordinate_map(dims):
    n = 100
    from modepy.tools import (
        unit_to_barycentric,
        barycentric_to_unit,
        barycentric_to_equilateral,
        equilateral_to_unit,
    )

    rng = np.random.Generator(np.random.PCG64(17))
    unit = nd.random_nodes_for_shape(shp.Simplex(dims), n, rng=rng)

    bary = unit_to_barycentric(unit)
    assert (np.abs(np.sum(bary, axis=0) - 1) < 1e-15).all()
    assert (bary >= 0).all()
    unit2 = barycentric_to_unit(bary)
    assert la.norm(unit - unit2) < 1e-14

    equi = barycentric_to_equilateral(bary)
    unit3 = equilateral_to_unit(equi)
    assert la.norm(unit - unit3) < 1e-14
예제 #10
0
파일: nodes.py 프로젝트: yjobic/modepy
def warp_and_blend_nodes_2d(n, node_tuples=None):
    try:
        alpha = _alpha_opt_2d[n - 1]
    except IndexError:
        alpha = 5 / 3

    space = PN(2, n)
    if node_tuples is None:
        node_tuples = node_tuples_for_space(space)
    else:
        if len(node_tuples) != space.space_dim:
            raise ValueError(
                "'node_tuples' list does not have the correct length")

    # shape: (2, nnodes)
    unit_nodes = (np.array(node_tuples, dtype=np.float64) / n * 2 - 1).T

    from modepy.tools import (unit_to_barycentric, barycentric_to_equilateral,
                              equilateral_to_unit)
    bary = unit_to_barycentric(unit_nodes)

    return equilateral_to_unit(
        barycentric_to_equilateral(bary) +
        _2d_equilateral_shift(n, bary, alpha))
예제 #11
0
파일: nodes.py 프로젝트: inducer/modepy
def warp_and_blend_nodes_3d(n, node_tuples=None):
    try:
        alpha = _alpha_opt_3d[n-1]
    except IndexError:
        alpha = 1.

    if node_tuples is None:
        from pytools import generate_nonnegative_integer_tuples_summing_to_at_most \
                as gnitstam
        node_tuples = list(gnitstam(n, 3))
    else:
        if len(node_tuples) != (n+1)*(n+2)*(n+3)//6:
            raise ValueError("node_tuples list does not have the correct length")

    # shape: (3, nnodes)
    unit_nodes = (np.array(node_tuples, dtype=np.float64)/n*2 - 1).T

    from modepy.tools import (
            unit_to_barycentric,
            barycentric_to_equilateral,
            equilateral_to_unit,
            EQUILATERAL_VERTICES)
    bary = unit_to_barycentric(unit_nodes)
    equi = barycentric_to_equilateral(bary)

    equi_vertices = EQUILATERAL_VERTICES[3]

    # total number of nodes and tolerance
    tol = 1e-8

    shift = np.zeros_like(equi)

    for i1, i2, i3, i4, vertex_step in [
            (0, 1, 2, 3, -1),
            (1, 2, 3, 0, -1),
            (2, 3, 0, 1, -1),
            (3, 0, 1, 2, -1),
            ]:

        vi2, vi3, vi4 = [(i1 + vertex_step*i) % 4 for i in range(1, 4)]

        # all vertices have the same distance from the origin
        tangent1 = equi_vertices[vi3] - equi_vertices[vi4]
        tangent1 /= la.norm(tangent1)

        tangent2 = equi_vertices[vi2] - equi_vertices[vi3]
        tangent2 -= np.dot(tangent1, tangent2)*tangent1

        tangent2 /= la.norm(tangent2)

        sub_bary = bary[[i2, i3, i4]]
        warp1, warp2 = _2d_equilateral_shift(n, sub_bary, alpha)

        l1 = bary[i1]
        l2, l3, l4 = sub_bary

        blend = l2*l3*l4

        denom = (l2+0.5*l1)*(l3+0.5*l1)*(l4+0.5*l1)
        denom_ok = denom > tol

        blend[denom_ok] = (
                (1+(alpha*l1[denom_ok])**2)
                * blend[denom_ok]
                / denom[denom_ok])

        shift = shift + (blend*warp1)[np.newaxis, :] * tangent1[:, np.newaxis]
        shift = shift + (blend*warp2)[np.newaxis, :] * tangent2[:, np.newaxis]

        is_face = (l1 < tol) & ((l2 > tol) | (l3 > tol) | (l4 > tol))

        # assign face warp separately
        shift[:, is_face] = (
                + warp1[is_face][np.newaxis, :] * tangent1[:, np.newaxis]
                + warp2[is_face][np.newaxis, :] * tangent2[:, np.newaxis]
                )

    return equilateral_to_unit(equi + shift)
예제 #12
0
link_radius = 0.02

from pytools import generate_nonnegative_integer_tuples_summing_to_at_most \
        as gnitstam
node_tuples = list(gnitstam(n, 3))
faces = [
        [nt for nt in node_tuples if nt[0] == 0],
        [nt for nt in node_tuples if nt[1] == 0],
        [nt for nt in node_tuples if nt[2] == 0],
        [nt for nt in node_tuples if sum(nt) == n]
        ]

from modepy.tools import unit_to_barycentric, barycentric_to_equilateral
nodes = [(n[0],n[2], n[1]) for n in
        barycentric_to_equilateral(
            unit_to_barycentric(
                mp.warp_and_blend_nodes(3, n, node_tuples))).T]
id_to_node = dict(list(zip(node_tuples, nodes)))

def get_ball_radius(nid):
    in_faces = len([f for f in faces if nid in f])
    if in_faces >= 2:
        return ball_radius * 1.333
    else:
        return ball_radius

def get_ball_color(nid):
    in_faces = len([f for f in faces if nid in f])
    if in_faces >= 2:
        return (1,0,1)
    else:
        return (0,0,1)
예제 #13
0
import matplotlib.pyplot as pt
import numpy as np
import modepy as mp

dims = 3
n = 10

unit = mp.warp_and_blend_nodes(dims, n)

if 0:
    from modepy.tools import estimate_lebesgue_constant
    lebesgue = estimate_lebesgue_constant(n, unit, visualize=True)

from modepy.tools import unit_to_barycentric, barycentric_to_equilateral
equi = barycentric_to_equilateral(unit_to_barycentric(unit))

if dims == 2:
    pt.plot(equi[0], equi[1], "o")

    from modepy.tools import EQUILATERAL_VERTICES
    uv = list(EQUILATERAL_VERTICES[2])
    uv.append(uv[0])
    uv = np.array(uv)
    pt.plot(uv[:, 0], uv[:, 1], "")

    pt.gca().set_aspect("equal")
    pt.show()
elif dims == 3:
    import mayavi.mlab as mlab
    mlab.points3d(equi[0], equi[1], equi[2])
    mlab.orientation_axes()
예제 #14
0
파일: nodes.py 프로젝트: userjjb/DbX
def warp_and_blend_nodes_3d(n, node_tuples=None):
    try:
        alpha = _alpha_opt_3d[n - 1]
    except IndexError:
        alpha = 1.

    if node_tuples is None:
        from pytools import generate_nonnegative_integer_tuples_summing_to_at_most \
                as gnitstam
        node_tuples = list(gnitstam(n, 3))
    else:
        if len(node_tuples) != (n + 1) * (n + 2) * (n + 3) // 6:
            raise ValueError(
                "node_tuples list does not have the correct length")

    # shape: (3, nnodes)
    unit_nodes = (np.array(node_tuples, dtype=np.float64) / n * 2 - 1).T

    from modepy.tools import (unit_to_barycentric, barycentric_to_equilateral,
                              equilateral_to_unit, EQUILATERAL_VERTICES)
    bary = unit_to_barycentric(unit_nodes)
    equi = barycentric_to_equilateral(bary)

    equi_vertices = EQUILATERAL_VERTICES[3]

    # total number of nodes and tolerance
    tol = 1e-8

    shift = np.zeros_like(equi)

    for i1, i2, i3, i4, vertex_step in [
        (0, 1, 2, 3, -1),
        (1, 2, 3, 0, -1),
        (2, 3, 0, 1, -1),
        (3, 0, 1, 2, -1),
    ]:

        vi2, vi3, vi4 = [(i1 + vertex_step * i) % 4 for i in range(1, 4)]

        # all vertices have the same distance from the origin
        tangent1 = equi_vertices[vi3] - equi_vertices[vi4]
        tangent1 /= la.norm(tangent1)

        tangent2 = equi_vertices[vi2] - equi_vertices[vi3]
        tangent2 -= np.dot(tangent1, tangent2) * tangent1

        tangent2 /= la.norm(tangent2)

        sub_bary = bary[[i2, i3, i4]]
        warp1, warp2 = _2d_equilateral_shift(n, sub_bary, alpha)

        l1 = bary[i1]
        l2, l3, l4 = sub_bary

        blend = l2 * l3 * l4

        denom = (l2 + 0.5 * l1) * (l3 + 0.5 * l1) * (l4 + 0.5 * l1)
        denom_ok = denom > tol

        blend[denom_ok] = ((1 + (alpha * l1[denom_ok])**2) * blend[denom_ok] /
                           denom[denom_ok])

        shift = shift + (blend * warp1)[np.newaxis, :] * tangent1[:,
                                                                  np.newaxis]
        shift = shift + (blend * warp2)[np.newaxis, :] * tangent2[:,
                                                                  np.newaxis]

        is_face = (l1 < tol) & ((l2 > tol) | (l3 > tol) | (l4 > tol))

        # assign face warp separately
        shift[:, is_face] = (
            +warp1[is_face][np.newaxis, :] * tangent1[:, np.newaxis] +
            warp2[is_face][np.newaxis, :] * tangent2[:, np.newaxis])

    return equilateral_to_unit(equi + shift)
예제 #15
0
n = 8

ball_radius = 0.05
link_radius = 0.02

from pytools import generate_nonnegative_integer_tuples_summing_to_at_most \
        as gnitstam
node_tuples = list(gnitstam(n, 3))
faces = [[nt for nt in node_tuples if nt[0] == 0],
         [nt for nt in node_tuples if nt[1] == 0],
         [nt for nt in node_tuples if nt[2] == 0],
         [nt for nt in node_tuples if sum(nt) == n]]

from modepy.tools import unit_to_barycentric, barycentric_to_equilateral
nodes = [(n[0], n[2], n[1]) for n in barycentric_to_equilateral(
    unit_to_barycentric(mp.warp_and_blend_nodes(3, n, node_tuples))).T]
id_to_node = dict(list(zip(node_tuples, nodes)))


def get_ball_radius(nid):
    in_faces = len([f for f in faces if nid in f])
    if in_faces >= 2:
        return ball_radius * 1.333
    else:
        return ball_radius


def get_ball_color(nid):
    in_faces = len([f for f in faces if nid in f])
    if in_faces >= 2:
        return (1, 0, 1)
예제 #16
0
from __future__ import absolute_import
import matplotlib.pyplot as pt
import numpy as np
import modepy as mp

dims = 3
n = 10

unit = mp.warp_and_blend_nodes(dims, n)

if 0:
    from modepy.tools import estimate_lebesgue_constant
    lebesgue = estimate_lebesgue_constant(n, unit, visualize=True)

from modepy.tools import unit_to_barycentric, barycentric_to_equilateral
equi = barycentric_to_equilateral(unit_to_barycentric(unit))

if dims == 2:
    pt.plot(equi[0], equi[1], "o")

    from modepy.tools import EQUILATERAL_VERTICES
    uv = list(EQUILATERAL_VERTICES[2])
    uv.append(uv[0])
    uv = np.array(uv)
    pt.plot(uv[:, 0], uv[:, 1], "")

    pt.gca().set_aspect("equal")
    pt.show()
elif dims == 3:
    import mayavi.mlab as mlab
    mlab.points3d(