Esempio n. 1
0
    def __init__(self, alpha, order):
        self.alpha = alpha
        self.warp = WarpFactorCalculator(order)

        cls = TriangleDiscretization

        from pytools import wandering_element
        from hedge.tools import normalize

        vertices = [
            cls.barycentric_to_equilateral(bary)
            for bary in wandering_element(cls.dimensions + 1)
        ]
        all_vertex_indices = range(cls.dimensions + 1)
        face_vertex_indices = cls.geometry \
                .face_vertices(all_vertex_indices)
        faces_vertices = cls.geometry.face_vertices(vertices)

        edgedirs = [normalize(v2 - v1) for v1, v2 in faces_vertices]
        opp_vertex_indices = [
            (set(all_vertex_indices) - set(fvi)).__iter__().next()
            for fvi in face_vertex_indices
        ]

        self.loop_info = zip(face_vertex_indices, edgedirs, opp_vertex_indices)
    def __init__(self, order, dimension):
        """
        :arg order: A parameter correlated with the total degree of polynomials
            that are integrated exactly. (See also :attr:`exact_to`.)
        :arg dimension: The number of dimensions for the quadrature rule.
            Any positive integer.
        """
        s = order
        n = dimension
        d = 2*s + 1

        self.exact_to = d

        if dimension == 0:
            nodes = np.zeros((dimension, 1))
            weights = np.ones(1)

            Quadrature.__init__(self, nodes, weights)
            return

        from pytools import \
                generate_decreasing_nonnegative_tuples_summing_to, \
                generate_unique_permutations, \
                factorial, \
                wandering_element

        points_to_weights = {}

        for i in range(s + 1):
            weight = (-1)**i * 2**(-2*s) \
                    * (d + n - 2*i)**d \
                    / factorial(i) \
                    / factorial(d + n - i)

            for t in generate_decreasing_nonnegative_tuples_summing_to(s - i, n + 1):
                for beta in generate_unique_permutations(t):
                    denominator = d + n - 2*i
                    point = tuple(
                            _simplify_fraction((2*beta_i + 1, denominator))
                            for beta_i in beta)

                    points_to_weights[point] = \
                            points_to_weights.get(point, 0) + weight

        from operator import add

        vertices = ([-1 * np.ones((n,))]
                + [np.array(x)
                    for x in wandering_element(n, landscape=-1, wanderer=1)])

        nodes = []
        weights = []

        dim_factor = 2**n
        for p, w in points_to_weights.items():
            real_p = reduce(add, (a/b * v for (a, b), v in zip(p, vertices)))
            nodes.append(real_p)
            weights.append(dim_factor * w)

        Quadrature.__init__(self, np.array(nodes).T, np.array(weights))
Esempio n. 3
0
def test_simplex_basis_grad(dims, order, basis_getter, grad_basis_getter):
    """Do a simplistic FD-style check on the gradients of the basis."""

    if dims == 3:
        err_factor = 3
    else:
        err_factor = 1

    from random import Random
    rng = Random(17)

    from modepy.tools import pick_random_simplex_unit_coordinate
    for i_bf, (bf, gradbf) in enumerate(
            zip(
                basis_getter(dims, order),
                grad_basis_getter(dims, order),
            )):
        for i in range(10):
            r = pick_random_simplex_unit_coordinate(rng, dims)

            from pytools import wandering_element
            h = 1e-4
            gradbf_v = np.array(gradbf(r))
            approx_gradbf_v = np.array([
                (bf(r + h * unit) - bf(r - h * unit)) / (2 * h) for unit in
                [np.array(unit) for unit in wandering_element(dims)]
            ])
            err = la.norm(approx_gradbf_v - gradbf_v, np.Inf)
            assert err < err_factor * h
Esempio n. 4
0
def test_simplex_basis_grad(dims, order, basis_getter, grad_basis_getter):
    """Do a simplistic FD-style check on the gradients of the basis."""

    if dims == 3:
        err_factor = 3
    else:
        err_factor = 1

    from random import Random
    rng = Random(17)

    from modepy.tools import pick_random_simplex_unit_coordinate
    for i_bf, (bf, gradbf) in enumerate(zip(
                basis_getter(dims, order),
                grad_basis_getter(dims, order),
                )):
        for i in range(10):
            r = pick_random_simplex_unit_coordinate(rng, dims)

            from pytools import wandering_element
            h = 1e-4
            gradbf_v = np.array(gradbf(r))
            approx_gradbf_v = np.array([
                (bf(r+h*unit) - bf(r-h*unit))/(2*h)
                for unit in [np.array(unit) for unit in wandering_element(dims)]
                ])
            err = la.norm(approx_gradbf_v-gradbf_v, np.Inf)
            assert err < err_factor*h
Esempio n. 5
0
    def __init__(self, order, dimension):
        """
        :arg order: A parameter correlated with the total degree of polynomials
            that are integrated exactly. (See also :attr:`exact_to`.)
        :arg dimension: The number of dimensions for the quadrature rule.
            Any positive integer.
        """
        s = order
        n = dimension
        d = 2*s+1

        self.exact_to = d

        if dimension == 0:
            nodes = np.zeros((dimension, 1))
            weights = np.ones(1)

            Quadrature.__init__(self, nodes, weights)
            return

        from pytools import \
                generate_decreasing_nonnegative_tuples_summing_to, \
                generate_unique_permutations, \
                factorial, \
                wandering_element

        points_to_weights = {}

        for i in range(s+1):
            weight = (-1)**i * 2**(-2*s) \
                    * (d + n-2*i)**d \
                    / factorial(i) \
                    / factorial(d+n-i)

            for t in generate_decreasing_nonnegative_tuples_summing_to(s-i, n+1):
                for beta in generate_unique_permutations(t):
                    denominator = d+n-2*i
                    point = tuple(
                            _simplify_fraction((2*beta_i+1, denominator))
                            for beta_i in beta)

                    points_to_weights[point] = \
                            points_to_weights.get(point, 0) + weight

        from operator import add

        vertices = [-1 * np.ones((n,))] \
                + [np.array(x)
                        for x in wandering_element(n, landscape=-1, wanderer=1)]

        nodes = []
        weights = []

        dim_factor = 2**n
        for p, w in six.iteritems(points_to_weights):
            real_p = reduce(add, (a/b*v for (a, b), v in zip(p, vertices)))
            nodes.append(real_p)
            weights.append(dim_factor*w)

        Quadrature.__init__(self, np.array(nodes).T, np.array(weights))
Esempio n. 6
0
    def __init__(self, alpha, order):
        self.alpha = alpha
        self.warp = WarpFactorCalculator(order)

        cls = TriangleDiscretization

        from pytools import wandering_element
        from hedge.tools import normalize

        vertices = [cls.barycentric_to_equilateral(bary)
                for bary in wandering_element(cls.dimensions + 1)]
        all_vertex_indices = range(cls.dimensions + 1)
        face_vertex_indices = cls.geometry \
                .face_vertices(all_vertex_indices)
        faces_vertices = cls.geometry.face_vertices(vertices)

        edgedirs = [normalize(v2 - v1) for v1, v2 in faces_vertices]
        opp_vertex_indices = [
            (set(all_vertex_indices) - set(fvi)).__iter__().next()
            for fvi in face_vertex_indices]

        self.loop_info = zip(
                face_vertex_indices,
                edgedirs,
                opp_vertex_indices)
Esempio n. 7
0
    def vertex_indices(self):
        """Return the list of the vertices' node indices."""
        from pytools import wandering_element

        result = []

        node_tup_to_idx = dict((ituple, idx) for idx, ituple in enumerate(self.node_tuples()))

        vertex_tuples = [self.dimensions * (0,)] + list(wandering_element(self.dimensions, wanderer=self.order))

        return [node_tup_to_idx[vt] for vt in vertex_tuples]
Esempio n. 8
0
    def vertex_indices(self):
        """Return the list of the vertices' node indices."""
        from pytools import wandering_element

        node_tup_to_idx = dict(
            (ituple, idx) for idx, ituple in enumerate(self.node_tuples()))

        vertex_tuples = [self.dimensions * (0,)] \
                + list(wandering_element(self.dimensions, wanderer=self.order))

        return [node_tup_to_idx[vt] for vt in vertex_tuples]
Esempio n. 9
0
def grad_tensor_product_basis(dims, basis_1d, grad_basis_1d):
    """Provides derivatives for each of the basis functions generated by
    :func:`tensor_product_basis`.

    :returns: a :class:`tuple` of callables, where each one returns a
        *dims*-dimensional :class:`tuple`, one for each derivative.

    .. versionadded:: 2020.2
    """
    from pytools import (
            wandering_element,
            generate_nonnegative_integer_tuples_below as gnitb)

    func = (basis_1d, grad_basis_1d)
    return tuple(
            _TensorProductGradientBasisFunction(order, [
                [func[i][k] for i, k in zip(iderivative, order)]
                for iderivative in wandering_element(dims)
                ])
            for order in gnitb(len(basis_1d), dims))
Esempio n. 10
0
def test_basis_grad(dims, order, eltype, basis_getter, grad_basis_getter):
    """Do a simplistic FD-style check on the gradients of the basis."""

    h = 1.0e-4
    if eltype == "simplex" and order == 8 and dims == 3:
        factor = 3.0
    else:
        factor = 1.0

    if eltype == "simplex":
        from modepy.tools import \
                pick_random_simplex_unit_coordinate as pick_random_unit_coordinate
    elif eltype == "tensor":
        from modepy.tools import \
                pick_random_hypercube_unit_coordinate as pick_random_unit_coordinate
    else:
        raise ValueError(f"unknown element type: {eltype}")

    from random import Random
    rng = Random(17)

    from pytools import wandering_element
    for i_bf, (bf, gradbf) in enumerate(
            zip(
                basis_getter(dims, order),
                grad_basis_getter(dims, order),
            )):
        for i in range(10):
            r = pick_random_unit_coordinate(rng, dims)

            gradbf_v = np.array(gradbf(r))
            gradbf_v_num = np.array([
                (bf(r + h * unit) - bf(r - h * unit)) / (2 * h)
                for unit_tuple in wandering_element(dims)
                for unit in (np.array(unit_tuple), )
            ])

            err = la.norm(gradbf_v_num - gradbf_v)
            logger.info("error: %.5", err)
            assert err < factor * h, (err, i_bf)
Esempio n. 11
0
def test_basis_grad(dim, shape_cls, order, basis_getter):
    """Do a simplistic FD-style check on the gradients of the basis."""

    h = 1.0e-4

    shape = shape_cls(dim)
    rng = np.random.Generator(np.random.PCG64(17))
    basis = basis_getter(mp.space_for_shape(shape, order), shape)

    from pytools.convergence import EOCRecorder
    from pytools import wandering_element
    for i_bf, (bf, gradbf) in enumerate(zip(
            basis.functions,
            basis.gradients,
    )):
        eoc_rec = EOCRecorder()
        for h in [1e-2, 1e-3]:
            r = mp.random_nodes_for_shape(shape, nnodes=1000, rng=rng)

            gradbf_v = np.array(gradbf(r))
            gradbf_v_num = np.array([
                (bf(r + h * unit) - bf(r - h * unit)) / (2 * h)
                for unit_tuple in wandering_element(shape.dim)
                for unit in (np.array(unit_tuple).reshape(-1, 1), )
            ])

            ref_norm = la.norm((gradbf_v).reshape(-1), np.inf)
            err = la.norm((gradbf_v_num - gradbf_v).reshape(-1), np.inf)
            if ref_norm > 1e-13:
                err = err / ref_norm

            logger.info("error: %.5", err)
            eoc_rec.add_data_point(h, err)

        tol = 1e-8
        if eoc_rec.max_error() >= tol:
            print(eoc_rec)
        assert (eoc_rec.max_error() < tol or eoc_rec.order_estimate() >= 1.5)
Esempio n. 12
0
def test_simp_basis_grad():
    """Do a simplistic FD-style check on the differentiation matrix"""
    from itertools import izip
    from hedge.discretization.local import \
            IntervalDiscretization, \
            TriangleDiscretization, \
            TetrahedronDiscretization
    from random import uniform

    els = [
            (1, IntervalDiscretization(5)),
            (1, TriangleDiscretization(8)),
            (3,TetrahedronDiscretization(7))]

    for err_factor, el in els:
        d = el.dimensions
        for i_bf, (bf, gradbf) in \
                enumerate(izip(el.basis_functions(), el.grad_basis_functions())):
            for i in range(10):
                base = -0.95
                remaining = 1.90
                r = numpy.zeros((d,))
                for i in range(d):
                    rn = uniform(0, remaining)
                    r[i] = base+rn
                    remaining -= rn

                from pytools import wandering_element
                h = 1e-4
                gradbf_v = numpy.array(gradbf(r))
                approx_gradbf_v = numpy.array([
                    (bf(r+h*dir) - bf(r-h*dir))/(2*h)
                    for dir in [numpy.array(dir) for dir in wandering_element(d)]
                    ])
                err = la.norm(approx_gradbf_v-gradbf_v, numpy.Inf)
                #print el.dimensions, el.order, i_bf, err
                assert err < err_factor*h
Esempio n. 13
0
def test_simp_basis_grad():
    """Do a simplistic FD-style check on the differentiation matrix"""
    from itertools import izip
    from hedge.discretization.local import \
            IntervalDiscretization, \
            TriangleDiscretization, \
            TetrahedronDiscretization
    from random import uniform

    els = [
            (1, IntervalDiscretization(5)),
            (1, TriangleDiscretization(8)),
            (3,TetrahedronDiscretization(7))]

    for err_factor, el in els:
        d = el.dimensions
        for i_bf, (bf, gradbf) in \
                enumerate(izip(el.basis_functions(), el.grad_basis_functions())):
            for i in range(10):
                base = -0.95
                remaining = 1.90
                r = numpy.zeros((d,))
                for i in range(d):
                    rn = uniform(0, remaining)
                    r[i] = base+rn
                    remaining -= rn

                from pytools import wandering_element
                h = 1e-4
                gradbf_v = numpy.array(gradbf(r))
                approx_gradbf_v = numpy.array([
                    (bf(r+h*dir) - bf(r-h*dir))/(2*h)
                    for dir in [numpy.array(dir) for dir in wandering_element(d)]
                    ])
                err = la.norm(approx_gradbf_v-gradbf_v, numpy.Inf)
                #print el.dimensions, el.order, i_bf, err
                assert err < err_factor*h
Esempio n. 14
0
    def __init__(self, order, dimension):
        s = order
        n = dimension
        d = 2 * s + 1

        self.exact_to = d

        from pytools import \
                generate_decreasing_nonnegative_tuples_summing_to, \
                generate_unique_permutations, \
                factorial, \
                wandering_element

        points_to_weights = {}

        for i in xrange(s + 1):
            weight = (-1)**i * 2**(-2*s) \
                    * (d + n-2*i)**d \
                    / factorial(i) \
                    / factorial(d+n-i)

            for t in generate_decreasing_nonnegative_tuples_summing_to(
                    s - i, n + 1):
                for beta in generate_unique_permutations(t):
                    denominator = d + n - 2 * i
                    point = tuple(
                        _simplify_fraction((2 * beta_i + 1, denominator))
                        for beta_i in beta)

                    points_to_weights[point] = points_to_weights.get(
                        point, 0) + weight

        from operator import add

        vertices = [-1 * numpy.ones((n,))] \
                + [numpy.array(x) for x in wandering_element(n, landscape=-1, wanderer=1)]

        self.pos_points = []
        self.pos_weights = []
        self.neg_points = []
        self.neg_weights = []

        dim_factor = 2**n
        for p, w in points_to_weights.iteritems():
            real_p = reduce(add, (a / b * v for (a, b), v in zip(p, vertices)))
            if w > 0:
                self.pos_points.append(real_p)
                self.pos_weights.append(dim_factor * w)
            else:
                self.neg_points.append(real_p)
                self.neg_weights.append(dim_factor * w)

        self.points = numpy.array(self.pos_points + self.neg_points)
        self.weights = numpy.array(self.pos_weights + self.neg_weights)

        self.pos_points = numpy.array(self.pos_points)
        self.pos_weights = numpy.array(self.pos_weights)
        self.neg_points = numpy.array(self.neg_points)
        self.neg_weights = numpy.array(self.neg_weights)

        self.points = numpy.array(self.points)
        self.weights = numpy.array(self.weights)

        self.pos_info = zip(self.pos_points, self.pos_weights)
        self.neg_info = zip(self.neg_points, self.neg_weights)
Esempio n. 15
0
    def __init__(self, order, dimension):
        s = order
        n = dimension
        d = 2*s+1

        self.exact_to = d

        from pytools import \
                generate_decreasing_nonnegative_tuples_summing_to, \
                generate_unique_permutations, \
                factorial, \
                wandering_element

        points_to_weights = {}

        for i in xrange(s+1):
            weight = (-1)**i * 2**(-2*s) \
                    * (d + n-2*i)**d \
                    / factorial(i) \
                    / factorial(d+n-i)

            for t in generate_decreasing_nonnegative_tuples_summing_to(s-i, n+1):
                for beta in generate_unique_permutations(t):
                    denominator = d+n-2*i
                    point = tuple(
                            _simplify_fraction((2*beta_i+1, denominator))
                            for beta_i in beta)

                    points_to_weights[point] = points_to_weights.get(point, 0) + weight

        from operator import add

        vertices = [-1 * numpy.ones((n,))] \
                + [numpy.array(x) for x in wandering_element(n, landscape=-1, wanderer=1)]

        self.pos_points = []
        self.pos_weights = []
        self.neg_points = []
        self.neg_weights = []

        dim_factor = 2**n
        for p, w in points_to_weights.iteritems():
            real_p = reduce(add, (a/b*v for (a,b),v in zip(p, vertices)))
            if w > 0:
                self.pos_points.append(real_p)
                self.pos_weights.append(dim_factor*w)
            else:
                self.neg_points.append(real_p)
                self.neg_weights.append(dim_factor*w)

        self.points = numpy.array(self.pos_points + self.neg_points)
        self.weights = numpy.array(self.pos_weights + self.neg_weights)

        self.pos_points = numpy.array(self.pos_points)
        self.pos_weights = numpy.array(self.pos_weights)
        self.neg_points = numpy.array(self.neg_points)
        self.neg_weights = numpy.array(self.neg_weights)

        self.points = numpy.array(self.points)
        self.weights = numpy.array(self.weights)

        self.pos_info = zip(self.pos_points, self.pos_weights)
        self.neg_info = zip(self.neg_points, self.neg_weights)
Esempio n. 16
0
    def equilateral_nodes(self):
        """Generate warped nodes in equilateral coordinates (x,y)."""

        # port of Hesthaven/Warburton's Nodes3D routine

        # Set optimized parameter alpha, depending on order N
        alpha_opt = [0, 0, 0, 0.1002, 1.1332, 1.5608, 1.3413, 1.2577, 1.1603,
                1.10153, 0.6080, 0.4523, 0.8856, 0.8717, 0.9655]
        if self.order-1 < len(alpha_opt):
            alpha = alpha_opt[self.order-1]
        else:
            alpha = 1

        from pytools import wandering_element

        vertices = [self.barycentric_to_equilateral(bary)
                for bary in wandering_element(self.dimensions + 1)]
        all_vertex_indices = range(self.dimensions + 1)
        face_vertex_indices = self.geometry \
                .face_vertices(all_vertex_indices)
        faces_vertices = self.geometry \
                .face_vertices(vertices)

        bary_points = list(self.equidistant_barycentric_nodes())
        equi_points = [self.barycentric_to_equilateral(bp)
                for bp in bary_points]

        from hedge.tools import normalize
        from operator import add, mul

        tri_warp = TriangleWarper(alpha, self.order)

        for fvi, (v1, v2, v3) in zip(face_vertex_indices, faces_vertices):
            # find directions spanning the face: "base" and "altitude"
            directions = [normalize(v2 - v1), normalize((v3)-(v1+v2)/2)]

            # the two should be orthogonal
            assert abs(numpy.dot(directions[0], directions[1])) < 1e-16

            # find the vertex opposite to the current face
            opp_vertex_index = (
                    set(all_vertex_indices)
                    - set(fvi)).__iter__().next()

            shifted = []
            for bp, ep in zip(bary_points, equi_points):
                face_bp = [bp[i] for i in fvi]

                blend = reduce(mul, face_bp) * (1+alpha*bp[opp_vertex_index])**2

                for i in fvi:
                    denom = bp[i] + 0.5*bp[opp_vertex_index]
                    if abs(denom) > 1e-12:
                        blend /= denom
                    else:
                        blend = 0.5  # each edge gets shifted twice
                        break

                shifted.append(ep + blend*reduce(add,
                    (tw*dir for tw, dir in zip(tri_warp(face_bp), directions))))

            equi_points = shifted

        return equi_points
Esempio n. 17
0
    def equilateral_nodes(self):
        """Generate warped nodes in equilateral coordinates (x,y)."""

        # port of Hesthaven/Warburton's Nodes3D routine

        # Set optimized parameter alpha, depending on order N
        alpha_opt = [
            0, 0, 0, 0.1002, 1.1332, 1.5608, 1.3413, 1.2577, 1.1603, 1.10153,
            0.6080, 0.4523, 0.8856, 0.8717, 0.9655
        ]
        if self.order - 1 < len(alpha_opt):
            alpha = alpha_opt[self.order - 1]
        else:
            alpha = 1

        from pytools import wandering_element

        vertices = [
            self.barycentric_to_equilateral(bary)
            for bary in wandering_element(self.dimensions + 1)
        ]
        all_vertex_indices = range(self.dimensions + 1)
        face_vertex_indices = self.geometry \
                .face_vertices(all_vertex_indices)
        faces_vertices = self.geometry \
                .face_vertices(vertices)

        bary_points = list(self.equidistant_barycentric_nodes())
        equi_points = [
            self.barycentric_to_equilateral(bp) for bp in bary_points
        ]

        from hedge.tools import normalize
        from operator import add, mul

        tri_warp = TriangleWarper(alpha, self.order)

        for fvi, (v1, v2, v3) in zip(face_vertex_indices, faces_vertices):
            # find directions spanning the face: "base" and "altitude"
            directions = [normalize(v2 - v1), normalize((v3) - (v1 + v2) / 2)]

            # the two should be orthogonal
            assert abs(numpy.dot(directions[0], directions[1])) < 1e-16

            # find the vertex opposite to the current face
            opp_vertex_index = (set(all_vertex_indices) -
                                set(fvi)).__iter__().next()

            shifted = []
            for bp, ep in zip(bary_points, equi_points):
                face_bp = [bp[i] for i in fvi]

                blend = reduce(mul,
                               face_bp) * (1 + alpha * bp[opp_vertex_index])**2

                for i in fvi:
                    denom = bp[i] + 0.5 * bp[opp_vertex_index]
                    if abs(denom) > 1e-12:
                        blend /= denom
                    else:
                        blend = 0.5  # each edge gets shifted twice
                        break

                shifted.append(ep + blend * reduce(add, (
                    tw * dir
                    for tw, dir in zip(tri_warp(face_bp), directions))))

            equi_points = shifted

        return equi_points