Esempio n. 1
0
File: p2p.py Progetto: inducer/sumpy
    def __call__(self, queue, targets, sources, index_set, **kwargs):
        """Construct a set of blocks of the full P2P interaction matrix.

        The blocks are returned as one-dimensional arrays, for performance
        and storage reasons. If the two-dimensional form is desired, it can
        be obtained using the information in the `index_set` for a block
        :math:`i` in the following way:

        .. code-block:: python

            blkranges = index_set.linear_ranges()
            blkshape = index_set.block_shape(i)

            block2d = result[blkranges[i]:blkranges[i + 1]].reshape(*blkshape)

        :arg targets: target point coordinates.
        :arg sources: source point coordinates.
        :arg index_set: a :class:`sumpy.tools.MatrixBlockIndexRanges` used
            to define the blocks.
        :return: a tuple of one-dimensional arrays of kernel evaluations at
            target-source pairs described by `index_set`.
        """
        from pytools.obj_array import is_obj_array
        knl = self.get_cached_optimized_kernel(
                targets_is_obj_array=(
                    is_obj_array(targets) or isinstance(targets, (tuple, list))),
                sources_is_obj_array=(
                    is_obj_array(sources) or isinstance(sources, (tuple, list))))

        return knl(queue,
                   targets=targets,
                   sources=sources,
                   tgtindices=index_set.linear_row_indices,
                   srcindices=index_set.linear_col_indices, **kwargs)
Esempio n. 2
0
    def __call__(self, queue, targets, sources, index_set, **kwargs):
        """Construct a set of blocks of the full P2P interaction matrix.

        The blocks are returned as one-dimensional arrays, for performance
        and storage reasons. If the two-dimensional form is desired, it can
        be obtained using the information in the `index_set` for a block
        :math:`i` in the following way:

        .. code-block:: python

            blkranges = index_set.linear_ranges()
            blkshape = index_set.block_shape(i)

            block2d = result[blkranges[i]:blkranges[i + 1]].reshape(*blkshape)

        :arg targets: target point coordinates.
        :arg sources: source point coordinates.
        :arg index_set: a :class:`sumpy.tools.MatrixBlockIndexRanges` used
            to define the blocks.
        :return: a tuple of one-dimensional arrays of kernel evaluations at
            target-source pairs described by `index_set`.
        """
        from pytools.obj_array import is_obj_array
        knl = self.get_cached_optimized_kernel(
            targets_is_obj_array=(is_obj_array(targets)
                                  or isinstance(targets, (tuple, list))),
            sources_is_obj_array=(is_obj_array(sources)
                                  or isinstance(sources, (tuple, list))))

        return knl(queue,
                   targets=targets,
                   sources=sources,
                   tgtindices=index_set.linear_row_indices,
                   srcindices=index_set.linear_col_indices,
                   **kwargs)
Esempio n. 3
0
def field_equal(a, b):
    a_is_oa = is_obj_array(a)
    assert a_is_oa == is_obj_array(b)

    if a_is_oa:
        return (a == b).all()
    else:
        return a == b
Esempio n. 4
0
def obj_array_equal(a, b):
    a_is_oa = is_obj_array(a)
    assert a_is_oa == is_obj_array(b)

    if a_is_oa:
        return np.array_equal(a, b)
    else:
        return a == b
Esempio n. 5
0
def obj_array_equal(a, b):
    a_is_oa = is_obj_array(a)
    assert a_is_oa == is_obj_array(b)

    if a_is_oa:
        return np.array_equal(a, b)
    else:
        return a == b
Esempio n. 6
0
    def __call__(self, queue, targets, sources, **kwargs):
        from pytools.obj_array import is_obj_array
        knl = self.get_cached_optimized_kernel(
            targets_is_obj_array=(is_obj_array(targets)
                                  or isinstance(targets, (tuple, list))),
            sources_is_obj_array=(is_obj_array(sources)
                                  or isinstance(sources, (tuple, list))))

        return knl(queue, sources=sources, targets=targets, **kwargs)
Esempio n. 7
0
File: p2p.py Progetto: inducer/sumpy
    def __call__(self, queue, targets, sources, **kwargs):
        from pytools.obj_array import is_obj_array
        knl = self.get_cached_optimized_kernel(
                targets_is_obj_array=(
                    is_obj_array(targets) or isinstance(targets, (tuple, list))),
                sources_is_obj_array=(
                    is_obj_array(sources) or isinstance(sources, (tuple, list))))

        return knl(queue, sources=sources, targets=targets, **kwargs)
Esempio n. 8
0
def separate_by_real_and_imag(data, real_only):
    for name, field in data:
        from pytools.obj_array import log_shape, is_obj_array
        ls = log_shape(field)

        if is_obj_array(field):
            assert len(ls) == 1
            from pytools.obj_array import (
                    oarray_real_copy, oarray_imag_copy,
                    with_object_array_or_scalar)

            if field[0].dtype.kind == "c":
                if real_only:
                    yield (name,
                            with_object_array_or_scalar(oarray_real_copy, field))
                else:
                    yield (name+"_r",
                            with_object_array_or_scalar(oarray_real_copy, field))
                    yield (name+"_i",
                            with_object_array_or_scalar(oarray_imag_copy, field))
            else:
                yield (name, field)
        else:
            # ls == ()
            if field.dtype.kind == "c":
                yield (name+"_r", field.real.copy())
                yield (name+"_i", field.imag.copy())
            else:
                yield (name, field)
Esempio n. 9
0
def with_object_array_or_scalar_n_args(f, *args):
    oarray_arg_indices = []
    for i, arg in enumerate(args):
        if is_obj_array(arg):
            oarray_arg_indices.append(i)

    if not oarray_arg_indices:
        return f(*args)

    leading_oa_index = oarray_arg_indices[0]

    ls = log_shape(args[leading_oa_index])
    if ls != ():
        from pytools import indices_in_shape
        result = np.zeros(ls, dtype=object)

        new_args = list(args)
        for i in indices_in_shape(ls):
            for arg_i in oarray_arg_indices:
                new_args[arg_i] = args[arg_i][i]

            result[i] = f(*new_args)
        return result
    else:
        return f(*args)
Esempio n. 10
0
def with_object_array_or_scalar_n_args(f, *args):
    oarray_arg_indices = []
    for i, arg in enumerate(args):
        if is_obj_array(arg):
            oarray_arg_indices.append(i)

    if not oarray_arg_indices:
        return f(*args)

    leading_oa_index = oarray_arg_indices[0]

    ls = log_shape(args[leading_oa_index])
    if ls != ():
        from pytools import indices_in_shape
        result = np.zeros(ls, dtype=object)

        new_args = list(args)
        for i in indices_in_shape(ls):
            for arg_i in oarray_arg_indices:
                new_args[arg_i] = args[arg_i][i]

            result[i] = f(*new_args)
        return result
    else:
        return f(*args)
Esempio n. 11
0
    def inverse_mass(self, vec):
        if is_obj_array(vec):
            return with_object_array_or_scalar(
                lambda el: self.inverse_mass(el), vec)

        @memoize_in(self, "elwise_linear_knl")
        def knl():
            knl = lp.make_kernel("""{[k,i,j]:
                    0<=k<nelements and
                    0<=i<ndiscr_nodes_out and
                    0<=j<ndiscr_nodes_in}""",
                                 "result[k,i] = sum(j, mat[i, j] * vec[k, j])",
                                 default_offset=lp.auto,
                                 name="diff")

            knl = lp.split_iname(knl, "i", 16, inner_tag="l.0")
            return lp.tag_inames(knl, dict(k="g.0"))

        discr = self.volume_discr

        result = discr.empty(queue=vec.queue, dtype=vec.dtype)

        for grp in discr.groups:
            matrix = self.get_inverse_mass_matrix(grp, vec.dtype)

            knl()(vec.queue,
                  mat=matrix,
                  result=grp.view(result),
                  vec=grp.view(vec))

        return result / self.vol_jacobian()
Esempio n. 12
0
def separate_by_real_and_imag(data, real_only):
    for name, field in data:
        from pytools.obj_array import log_shape, is_obj_array
        ls = log_shape(field)

        if is_obj_array(field):
            assert len(ls) == 1
            from pytools.obj_array import (oarray_real_copy, oarray_imag_copy,
                                           with_object_array_or_scalar)

            if field[0].dtype.kind == "c":
                if real_only:
                    yield (name,
                           with_object_array_or_scalar(oarray_real_copy,
                                                       field))
                else:
                    yield (name + "_r",
                           with_object_array_or_scalar(oarray_real_copy,
                                                       field))
                    yield (name + "_i",
                           with_object_array_or_scalar(oarray_imag_copy,
                                                       field))
            else:
                yield (name, field)
        else:
            # ls == ()
            if field.dtype.kind == "c":
                yield (name + "_r", field.real.copy())
                yield (name + "_i", field.imag.copy())
            else:
                yield (name, field)
Esempio n. 13
0
    def scipy_op(self, queue, arg_name, domains=None, **extra_args):
        """
        :arg domains: a list of discretization identifiers or
            *None* values indicating the domains on which each component of the
            solution vector lives.  *None* values indicate that the component
            is a scalar.  If *None*,
            :class:`pytential.symbolic.primitives.DEFAULT_TARGET`, is required
            to be a key in :attr:`places`.
        """

        from pytools.obj_array import is_obj_array

        if domains is None:
            from pytential.symbolic.primitives import DEFAULT_TARGET
            if DEFAULT_TARGET not in self.places:
                raise RuntimeError("'domains is None' requires "
                        "DEFAULT_TARGET to be defined")
            dom_name = DEFAULT_TARGET
            if is_obj_array(self.code.result):
                domains = len(self.code.result)*[dom_name]
            else:
                domains = [dom_name]
        elif not isinstance(domains, list):
            dom_name = domains
            if is_obj_array(self.code.result):
                domains = len(self.code.result)*[dom_name]
            else:
                domains = [dom_name]

        total_dofs = 0
        starts_and_ends = []
        for dom_name in domains:
            if dom_name is None:
                size = 1
            else:
                size = self.places[dom_name].nnodes

            starts_and_ends.append((total_dofs, total_dofs+size))
            total_dofs += size

        # Hidden assumption: Number of input components
        # equals number of output compoments. But IMO that's
        # fair, since these operators are usually only used
        # for linear system solving, in which case the assumption
        # has to be true.
        return MatVecOp(self, queue,
                arg_name, total_dofs, starts_and_ends, extra_args)
Esempio n. 14
0
    def reorder_potentials(self, potentials):
        from pytools.obj_array import is_obj_array, with_object_array_or_scalar
        assert is_obj_array(potentials)

        def reorder(x):
            return x.with_queue(self.queue)[self.tree.sorted_target_ids]

        return with_object_array_or_scalar(reorder, potentials)
Esempio n. 15
0
    def reorder_potentials(self, potentials):
        from pytools.obj_array import is_obj_array, with_object_array_or_scalar
        assert is_obj_array(potentials)

        def reorder(x):
            return x.with_queue(self.queue)[self.tree.sorted_target_ids]

        return with_object_array_or_scalar(reorder, potentials)
Esempio n. 16
0
def get_array_module(vec):
    try:
        from pyopencl.tools import array_module
        from pytools.obj_array import is_obj_array
        if is_obj_array(vec):
            return array_module(vec[0])
        else:
            return array_module(vec)
    except ImportError:
        return np
Esempio n. 17
0
    def vec_times(self, vec, operand):
        from pytools.obj_array import is_obj_array

        if is_obj_array(operand):
            if len(operand) != self.dimensions:
                raise ValueError("operand of vec_times must have %d dimensions"
                        % self.dimensions)

            return np.dot(vec, operand)
        else:
            return vec*operand
Esempio n. 18
0
    def apply_diff(self, nabla, operand):
        from pytools.obj_array import make_obj_array, is_obj_array
        if is_obj_array(operand):
            if len(operand) != self.dimensions:
                raise ValueError("operand of apply_diff must have %d dimensions"
                        % self.dimensions)

            return sum(nabla[i](operand[i]) for i in range(self.dimensions))
        else:
            return make_obj_array(
                [nabla[i](operand) for i in range(self.dimensions)])
Esempio n. 19
0
def dot_dataflow_graph(code, max_node_label_length=30,
        label_wrap_width=50):
    origins = {}
    node_names = {}

    result = [
            "initial [label=\"initial\"]"
            "result [label=\"result\"]"]

    for num, insn in enumerate(code.instructions):
        node_name = "node%d" % num
        node_names[insn] = node_name
        node_label = str(insn)

        if max_node_label_length is not None:
            node_label = node_label[:max_node_label_length]

        if label_wrap_width is not None:
            from pytools import word_wrap
            node_label = word_wrap(node_label, label_wrap_width,
                    wrap_using="\n      ")

        node_label = node_label.replace("\n", "\\l") + "\\l"

        result.append("%s [ label=\"p%d: %s\" shape=box ];" % (
            node_name, insn.priority, node_label))

        for assignee in insn.get_assignees():
            origins[assignee] = node_name

    def get_orig_node(expr):
        from pymbolic.primitives import Variable
        if isinstance(expr, Variable):
            return origins.get(expr.name, "initial")
        else:
            return "initial"

    def gen_expr_arrow(expr, target_node):
        result.append("%s -> %s [label=\"%s\"];"
                % (get_orig_node(expr), target_node, expr))

    for insn in code.instructions:
        for dep in insn.get_dependencies():
            gen_expr_arrow(dep, node_names[insn])

    from pytools.obj_array import is_obj_array

    if is_obj_array(code.result):
        for subexp in code.result:
            gen_expr_arrow(subexp, "result")
    else:
        gen_expr_arrow(code.result, "result")

    return "digraph dataflow {\n%s\n}\n" % "\n".join(result)
Esempio n. 20
0
def dot_dataflow_graph(code, max_node_label_length=30, label_wrap_width=50):
    origins = {}
    node_names = {}

    result = ["initial [label=\"initial\"]" "result [label=\"result\"]"]

    for num, insn in enumerate(code.instructions):
        node_name = "node%d" % num
        node_names[insn] = node_name
        node_label = str(insn)

        if (max_node_label_length is not None
                and not isinstance(insn, LoopyKernelInstruction)):
            node_label = node_label[:max_node_label_length]

        if label_wrap_width is not None:
            from pytools import word_wrap
            node_label = word_wrap(node_label,
                                   label_wrap_width,
                                   wrap_using="\n      ")

        node_label = node_label.replace("\n", "\\l") + "\\l"

        result.append("%s [ label=\"p%d: %s\" shape=box ];" %
                      (node_name, insn.priority, node_label))

        for assignee in insn.get_assignees():
            origins[assignee] = node_name

    def get_orig_node(expr):
        from pymbolic.primitives import Variable
        if isinstance(expr, Variable):
            return origins.get(expr.name, "initial")
        else:
            return "initial"

    def gen_expr_arrow(expr, target_node):
        result.append("%s -> %s [label=\"%s\"];" %
                      (get_orig_node(expr), target_node, expr))

    for insn in code.instructions:
        for dep in insn.get_dependencies():
            gen_expr_arrow(dep, node_names[insn])

    from pytools.obj_array import is_obj_array

    if is_obj_array(code.result):
        for subexp in code.result:
            gen_expr_arrow(subexp, "result")
    else:
        gen_expr_arrow(code.result, "result")

    return "digraph dataflow {\n%s\n}\n" % "\n".join(result)
Esempio n. 21
0
    def vec_times(self, vec, operand):
        from pytools.obj_array import is_obj_array

        if is_obj_array(operand):
            if len(operand) != self.dimensions:
                raise ValueError(
                    "operand of vec_times must have %d dimensions" %
                    self.dimensions)

            return np.dot(vec, operand)
        else:
            return vec * operand
Esempio n. 22
0
    def apply_diff(self, nabla, operand):
        from pytools.obj_array import make_obj_array, is_obj_array
        if is_obj_array(operand):
            if len(operand) != self.dimensions:
                raise ValueError(
                    "operand of apply_diff must have %d dimensions" %
                    self.dimensions)

            return sum(nabla[i](operand[i]) for i in range(self.dimensions))
        else:
            return make_obj_array(
                [nabla[i](operand) for i in range(self.dimensions)])
Esempio n. 23
0
    def __call__(self, discr, t, fields, x, make_empty):
        result = self.make_func(discr)(t=numpy.float64(t), x=x, fields=fields)

        # make sure we return no scalars in the result
        from pytools.obj_array import log_shape, is_obj_array
        if is_obj_array(result):
            from pytools import indices_in_shape
            from hedge.optemplate.tools import is_scalar
            for i in indices_in_shape(log_shape(result)):
                if is_scalar(result[i]):
                    result[i] = make_empty().fill(result[i])

        return result
Esempio n. 24
0
    def __call__(self, operand, *args, **kwargs):
        # If the call is handed an object array full of operands,
        # return an object array of the operator applied to each of the
        # operands.

        from pytools.obj_array import is_obj_array, with_object_array_or_scalar
        if is_obj_array(operand):
            def make_op(operand_i):
                return self(operand_i, *args, **kwargs)

            return with_object_array_or_scalar(make_op, operand)
        else:
            return var.__call__(self, operand, *args, **kwargs)
Esempio n. 25
0
    def __call__(self, discr, t, fields, x, make_empty):
        result = self.make_func(discr)(
                t=numpy.float64(t), x=x, fields=fields)

        # make sure we return no scalars in the result
        from pytools.obj_array import log_shape, is_obj_array
        if is_obj_array(result):
            from pytools import indices_in_shape
            from hedge.optemplate.tools import is_scalar
            for i in indices_in_shape(log_shape(result)):
                if is_scalar(result[i]):
                    result[i] = make_empty().fill(result[i])

        return result
Esempio n. 26
0
def with_object_array_or_scalar(f, field, obj_array_only=False):
    if obj_array_only:
        if is_obj_array(field):
            ls = field.shape
        else:
            ls = ()
    else:
        ls = log_shape(field)
    if ls != ():
        from pytools import indices_in_shape
        result = np.zeros(ls, dtype=object)
        for i in indices_in_shape(ls):
            result[i] = f(field[i])
        return result
    else:
        return f(field)
Esempio n. 27
0
def with_object_array_or_scalar(f, field, obj_array_only=False):
    if obj_array_only:
        if is_obj_array(field):
            ls = field.shape
        else:
            ls = ()
    else:
        ls = log_shape(field)
    if ls != ():
        from pytools import indices_in_shape
        result = np.zeros(ls, dtype=object)
        for i in indices_in_shape(ls):
            result[i] = f(field[i])
        return result
    else:
        return f(field)
Esempio n. 28
0
    def __init__(self, structured_vec):
        from pytools.obj_array import is_obj_array
        self.is_structured = is_obj_array(structured_vec)
        self.array_module = get_array_module(structured_vec)

        if self.is_structured:
            self.slices = []
            num_dofs = 0
            for entry in structured_vec:
                if isinstance(entry, self.array_module.ndarray):
                    length = len(entry)
                else:
                    length = 1

                self.slices.append(slice(num_dofs, num_dofs+length))
                num_dofs += length
Esempio n. 29
0
    def face_mass(self, vec):
        if is_obj_array(vec):
            return with_object_array_or_scalar(lambda el: self.face_mass(el),
                                               vec)

        @memoize_in(self, "face_mass_knl")
        def knl():
            knl = lp.make_kernel(
                """{[k,i,f,j]:
                    0<=k<nelements and
                    0<=f<nfaces and
                    0<=i<nvol_nodes and
                    0<=j<nface_nodes}""",
                "result[k,i] = sum(f, sum(j, mat[i, f, j] * vec[f, k, j]))",
                default_offset=lp.auto,
                name="face_mass")

            knl = lp.split_iname(knl, "i", 16, inner_tag="l.0")
            return lp.tag_inames(knl, dict(k="g.0"))

        all_faces_conn = self.get_connection("vol", "all_faces")
        all_faces_discr = all_faces_conn.to_discr
        vol_discr = all_faces_conn.from_discr

        result = vol_discr.empty(queue=vec.queue, dtype=vec.dtype)

        fj = self.face_jacobian("all_faces")
        vec = vec * fj

        assert len(all_faces_discr.groups) == len(vol_discr.groups)

        for afgrp, volgrp in zip(all_faces_discr.groups, vol_discr.groups):
            nfaces = volgrp.mesh_el_group.nfaces

            matrix = self.get_local_face_mass_matrix(afgrp, volgrp, vec.dtype)

            input_view = afgrp.view(vec).reshape(nfaces, volgrp.nelements,
                                                 afgrp.nunit_nodes)
            knl()(vec.queue,
                  mat=matrix,
                  result=volgrp.view(result),
                  vec=input_view)

        return result
Esempio n. 30
0
def dd_axis(axis, ambient_dim, operand):
    """Return the derivative along (XYZ) axis *axis*
    (in *ambient_dim*-dimensional space) of *operand*.
    """
    from pytools.obj_array import is_obj_array, with_object_array_or_scalar
    if is_obj_array(operand):
        def dd_axis_comp(operand_i):
            return dd_axis(axis, ambient_dim, operand_i)

        return with_object_array_or_scalar(dd_axis_comp, operand)

    d = Derivative()

    unit_vector = np.zeros(ambient_dim)
    unit_vector[axis] = 1

    unit_mvector = MultiVector(unit_vector)

    return d.resolve(
            (unit_mvector.scalar_product(d.dnabla(ambient_dim)))
            * d(operand))
Esempio n. 31
0
    def scipy_op(self, queue, arg_name, dtype, domains=None, **extra_args):
        """
        :arg domains: a list of discretization identifiers or
            *None* values indicating the domains on which each component of the
            solution vector lives.  *None* values indicate that the component
            is a scalar.  If *domains* is *None*,
            :class:`~pytential.symbolic.primitives.DEFAULT_TARGET` is required
            to be a key in :attr:`places`.
        :returns: An object that (mostly) satisfies the
            :mod:`scipy.linalg.LinearOperator` protocol, except for accepting
            and returning :clas:`pyopencl.array.Array` arrays.
        """

        from pytools.obj_array import is_obj_array
        if is_obj_array(self.code.result):
            nresults = len(self.code.result)
        else:
            nresults = 1

        domains = _prepare_domains(nresults, self.places, domains,
                                   self.places.auto_target)

        total_dofs = 0
        starts_and_ends = []
        for dom_name in domains:
            if dom_name is None:
                size = 1
            else:
                size = self.places.get_geometry(dom_name).nnodes

            starts_and_ends.append((total_dofs, total_dofs + size))
            total_dofs += size

        # Hidden assumption: Number of input components
        # equals number of output compoments. But IMO that's
        # fair, since these operators are usually only used
        # for linear system solving, in which case the assumption
        # has to be true.
        return MatVecOp(self, queue, arg_name, dtype, total_dofs,
                        starts_and_ends, extra_args)
Esempio n. 32
0
def test_matrix_build(ctx_factory, k, curve_f, lpot_id, visualize=False):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)

    # prevent cache 'splosion
    from sympy.core.cache import clear_cache
    clear_cache()

    target_order = 7
    qbx_order = 4
    nelements = 30
    mesh = make_curve_mesh(curve_f,
            np.linspace(0, 1, nelements + 1),
            target_order)

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory
    pre_density_discr = Discretization(
            cl_ctx, mesh,
            InterpolatoryQuadratureSimplexGroupFactory(target_order))

    from pytential.qbx import QBXLayerPotentialSource
    qbx, _ = QBXLayerPotentialSource(pre_density_discr, 4 * target_order,
            qbx_order,
            # Don't use FMM for now
            fmm_order=False).with_refinement()
    density_discr = qbx.density_discr

    op, u_sym, knl_kwargs = _build_op(lpot_id, k=k)
    bound_op = bind(qbx, op)

    from pytential.symbolic.execution import build_matrix
    mat = build_matrix(queue, qbx, op, u_sym).get()

    if visualize:
        from sumpy.tools import build_matrix as build_matrix_via_matvec
        mat2 = bound_op.scipy_op(queue, "u", dtype=mat.dtype, **knl_kwargs)
        mat2 = build_matrix_via_matvec(mat2)
        print(la.norm((mat - mat2).real, "fro") / la.norm(mat2.real, "fro"),
              la.norm((mat - mat2).imag, "fro") / la.norm(mat2.imag, "fro"))

        import matplotlib.pyplot as pt
        pt.subplot(121)
        pt.imshow(np.log10(np.abs(1.0e-20 + (mat - mat2).real)))
        pt.colorbar()
        pt.subplot(122)
        pt.imshow(np.log10(np.abs(1.0e-20 + (mat - mat2).imag)))
        pt.colorbar()
        pt.show()

    if visualize:
        import matplotlib.pyplot as pt
        pt.subplot(121)
        pt.imshow(mat.real)
        pt.colorbar()
        pt.subplot(122)
        pt.imshow(mat.imag)
        pt.colorbar()
        pt.show()

    from sumpy.tools import vector_to_device, vector_from_device
    np.random.seed(12)
    for i in range(5):
        if is_obj_array(u_sym):
            u = make_obj_array([
                np.random.randn(density_discr.nnodes)
                for _ in range(len(u_sym))
                ])
        else:
            u = np.random.randn(density_discr.nnodes)

        u_dev = vector_to_device(queue, u)
        res_matvec = np.hstack(
                list(vector_from_device(
                    queue, bound_op(queue, u=u_dev))))

        res_mat = mat.dot(np.hstack(list(u)))

        abs_err = la.norm(res_mat - res_matvec, np.inf)
        rel_err = abs_err / la.norm(res_matvec, np.inf)

        print("AbsErr {:.5e} RelErr {:.5e}".format(abs_err, rel_err))
        assert rel_err < 1e-13
Esempio n. 33
0
def is_field_equal(a, b):
    if is_obj_array(a):
        return is_obj_array(b) and (a.shape == b.shape) and (a == b).all()
    else:
        return not is_obj_array(b) and a == b
Esempio n. 34
0
def aggregate_assignments(inf_mapper, instructions, result,
                          max_vectors_in_batch_expr):
    from pymbolic.primitives import Variable

    function_registry = inf_mapper.function_registry

    # {{{ aggregation helpers

    def get_complete_origins_set(insn, skip_levels=0):
        try:
            return insn_to_origins_cache[insn]
        except KeyError:
            pass

        if skip_levels < 0:
            skip_levels = 0

        result = set()
        for dep in insn.get_dependencies():
            if isinstance(dep, Variable):
                dep_origin = origins_map.get(dep.name, None)
                if dep_origin is not None:
                    if skip_levels <= 0:
                        result.add(dep_origin)
                    result |= get_complete_origins_set(dep_origin,
                                                       skip_levels - 1)

        insn_to_origins_cache[insn] = result

        return result

    var_assignees_cache = {}

    def get_var_assignees(insn):
        try:
            return var_assignees_cache[insn]
        except KeyError:
            result = set(
                Variable(assignee) for assignee in insn.get_assignees())
            var_assignees_cache[insn] = result
            return result

    def aggregate_two_assignments(ass_1, ass_2):
        names = ass_1.names + ass_2.names

        from pymbolic.primitives import Variable
        deps = (ass_1.get_dependencies() | ass_2.get_dependencies()) \
                - set(Variable(name) for name in names)

        return Assign(names=names,
                      exprs=ass_1.exprs + ass_2.exprs,
                      _dependencies=deps,
                      priority=max(ass_1.priority, ass_2.priority))

    # }}}

    # {{{ main aggregation pass

    insn_to_origins_cache = {}

    origins_map = dict((assignee, insn) for insn in instructions
                       for assignee in insn.get_assignees())

    from pytools import partition
    from grudge.symbolic.primitives import DTAG_SCALAR

    unprocessed_assigns, other_insns = partition(
        lambda insn: (isinstance(insn, Assign) and not isinstance(
            insn, ToDiscretizationScopedAssign) and not isinstance(
                insn, FromDiscretizationScopedAssign) and not is_external_call(
                    insn.exprs[0], function_registry) and not any(
                        inf_mapper.infer_for_name(n).domain_tag == DTAG_SCALAR
                        for n in insn.names)), instructions)

    # filter out zero-flop-count assigns--no need to bother with those
    processed_assigns, unprocessed_assigns = partition(
        lambda ass: ass.flop_count() == 0, unprocessed_assigns)

    # filter out zero assignments
    from grudge.tools import is_zero

    i = 0

    while i < len(unprocessed_assigns):
        my_assign = unprocessed_assigns[i]
        if any(is_zero(expr) for expr in my_assign.exprs):
            processed_assigns.append(unprocessed_assigns.pop(i))
        else:
            i += 1

    # greedy aggregation
    while unprocessed_assigns:
        my_assign = unprocessed_assigns.pop()

        my_deps = my_assign.get_dependencies()
        my_assignees = get_var_assignees(my_assign)

        agg_candidates = []
        for i, other_assign in enumerate(unprocessed_assigns):
            other_deps = other_assign.get_dependencies()
            other_assignees = get_var_assignees(other_assign)

            if ((my_deps & other_deps or my_deps & other_assignees
                 or other_deps & my_assignees)
                    and my_assign.priority == other_assign.priority):
                agg_candidates.append((i, other_assign))

        did_work = False

        if agg_candidates:
            my_indirect_origins = get_complete_origins_set(my_assign,
                                                           skip_levels=1)

            for other_assign_index, other_assign in agg_candidates:
                if max_vectors_in_batch_expr is not None:
                    new_assignee_count = len(
                        set(my_assign.get_assignees())
                        | set(other_assign.get_assignees()))
                    new_dep_count = len(
                        my_assign.get_dependencies(each_vector=True)
                        | other_assign.get_dependencies(each_vector=True))

                    if (new_assignee_count + new_dep_count >
                            max_vectors_in_batch_expr):
                        continue

                other_indirect_origins = get_complete_origins_set(
                    other_assign, skip_levels=1)

                if (my_assign not in other_indirect_origins
                        and other_assign not in my_indirect_origins):
                    did_work = True

                    # aggregate the two assignments
                    new_assignment = aggregate_two_assignments(
                        my_assign, other_assign)
                    del unprocessed_assigns[other_assign_index]
                    unprocessed_assigns.append(new_assignment)
                    for assignee in new_assignment.get_assignees():
                        origins_map[assignee] = new_assignment

                    break

        if not did_work:
            processed_assigns.append(my_assign)

    externally_used_names = set(expr
                                for insn in processed_assigns + other_insns
                                for expr in insn.get_dependencies())

    from pytools.obj_array import is_obj_array
    if is_obj_array(result):
        externally_used_names |= set(expr for expr in result)
    else:
        externally_used_names |= set([result])

    def schedule_and_finalize_assignment(ass):
        dep_mapper = _make_dep_mapper(include_subscripts=False)

        names_exprs = list(zip(ass.names, ass.exprs))

        my_assignees = set(name for name, expr in names_exprs)
        names_exprs_deps = [
            (name, expr,
             set(dep.name
                 for dep in dep_mapper(expr) if isinstance(dep, Variable))
             & my_assignees) for name, expr in names_exprs
        ]

        ordered_names_exprs = []
        available_names = set()

        while names_exprs_deps:
            schedulable = []

            i = 0
            while i < len(names_exprs_deps):
                name, expr, deps = names_exprs_deps[i]

                unsatisfied_deps = deps - available_names

                if not unsatisfied_deps:
                    schedulable.append((str(expr), name, expr))
                    del names_exprs_deps[i]
                else:
                    i += 1

            # make sure these come out in a constant order
            schedulable.sort()

            if schedulable:
                for key, name, expr in schedulable:
                    ordered_names_exprs.append((name, expr))
                    available_names.add(name)
            else:
                raise RuntimeError("aggregation resulted in an "
                                   "impossible assignment")

        return Assign(names=[name for name, expr in ordered_names_exprs],
                      exprs=[expr for name, expr in ordered_names_exprs],
                      do_not_return=[
                          Variable(name) not in externally_used_names
                          for name, expr in ordered_names_exprs
                      ],
                      priority=ass.priority)

    return [
        schedule_and_finalize_assignment(ass) for ass in processed_assigns
    ] + other_insns
Esempio n. 35
0
 def apply_imag(self, args):
     from pytools.obj_array import is_obj_array
     arg, = args
     result = self.rec(arg)
     assert not is_obj_array(result)  # numpy bug with obj_array.imag
     return result.imag
Esempio n. 36
0
def hashable_field(f):
    if is_obj_array(f):
        return tuple(f)
    else:
        return f
Esempio n. 37
0
def obj_array_to_hashable(f):
    if is_obj_array(f):
        return tuple(f)
    else:
        return f
Esempio n. 38
0
 def apply_imag(self, args):
     from pytools.obj_array import is_obj_array
     arg, = args
     result = self.rec(arg)
     assert not is_obj_array(result)  # numpy bug with obj_array.imag
     return result.imag
Esempio n. 39
0
def setify_field(f):
    from hedge.tools import is_obj_array
    if is_obj_array(f):
        return set(f)
    else:
        return set([f])
Esempio n. 40
0
def gen_len(expr):
    from pytools.obj_array import is_obj_array
    if is_obj_array(expr):
        return len(expr)
    else:
        return 1
Esempio n. 41
0
def gmres(op,
          rhs,
          restart=None,
          tol=None,
          x0=None,
          inner_product=None,
          maxiter=None,
          hard_failure=None,
          no_progress_factor=None,
          stall_iterations=None,
          callback=None,
          progress=False):
    """Solve a linear system Ax=b by means of GMRES
with restarts.

:arg op: a callable to evaluate A(x)
:arg b: the right hand side
:arg restart: the maximum number of iteration after
which GMRES algorithm needs to be restarted
:arg tol: the required decrease in residual norm
:arg inner_product: Must have an interface compatible with
:func:`numpy.vdot`. Must return a host scalar.
:arg maxiter: the maximum number of iteration permitted
:arg hard_failure: If True, raise :exc:`GMRESError` in case of failure.
:arg stall_iterations: Number of iterations with residual decrease
below *no_progress_factor* indicates stall. Set to 0 to disable
stall detection.

:return: a :class:`GMRESResult`
"""
    try:
        from pyopencl.tools import array_module
        amod = array_module(rhs)
    except ImportError:
        amod = np

    from pytools.obj_array import is_obj_array, make_obj_array
    if is_obj_array(rhs):
        stacked_rhs = amod.hstack(rhs)

        slices = []
        num_dofs = 0
        for entry in rhs:
            if isinstance(entry, amod.ndarray):
                length = len(entry)
            else:
                length = 1

            slices.append(slice(num_dofs, num_dofs + length))
            num_dofs += length

    else:
        stacked_rhs = rhs

    if inner_product is None:
        inner_product = amod.vdot

    if callback is None:
        if progress:
            callback = ResidualPrinter(inner_product)
        else:
            callback = None

    result = _gmres(op,
                    stacked_rhs,
                    restart=restart,
                    tol=tol,
                    x0=x0,
                    dot=inner_product,
                    maxiter=maxiter,
                    hard_failure=hard_failure,
                    no_progress_factor=no_progress_factor,
                    stall_iterations=stall_iterations,
                    callback=callback)

    if is_obj_array(rhs):
        return result.copy(
            solution=make_obj_array([result.solution[slc] for slc in slices]))
    else:
        return result
Esempio n. 42
0
    def interp(self, src, tgt, vec):
        if is_obj_array(vec):
            return with_object_array_or_scalar(
                lambda el: self.interp(src, tgt, el), vec)

        return self.get_connection(src, tgt)(vec.queue, vec)
Esempio n. 43
0
def is_equal(a, b):
    if is_obj_array(a):
        return is_obj_array(b) and (a.shape == b.shape) and (a == b).all()
    else:
        return not is_obj_array(b) and a == b
Esempio n. 44
0
def gen_len(expr):
    from pytools.obj_array import is_obj_array
    if is_obj_array(expr):
        return len(expr)
    else:
        return 1
Esempio n. 45
0
def obj_array_to_hashable(f):
    if is_obj_array(f):
        return tuple(f)
    else:
        return f
Esempio n. 46
0
def setify_field(f):
    from hedge.tools import is_obj_array
    if is_obj_array(f):
        return set(f)
    else:
        return set([f])
Esempio n. 47
0
def build_matrix(queue,
                 places,
                 exprs,
                 input_exprs,
                 domains=None,
                 auto_where=None,
                 context=None):
    """
    :arg queue: a :class:`pyopencl.CommandQueue`.
    :arg places: a :class:`pytential.symbolic.execution.GeometryCollection`.
        Alternatively, any list or mapping that is a valid argument for its
        constructor can also be used.
    :arg exprs: an array of expressions corresponding to the output block
        rows of the matrix. May also be a single expression.
    :arg input_exprs: an array of expressions corresponding to the
        input block columns of the matrix. May also be a single expression.
    :arg domains: a list of discretization identifiers (see 'places') or
        *None* values indicating the domains on which each component of the
        solution vector lives.  *None* values indicate that the component
        is a scalar.  If *None*, *auto_where* or, if it is not provided,
        :class:`~pytential.symbolic.primitives.DEFAULT_SOURCE` is required
        to be a key in :attr:`places`.
    :arg auto_where: For simple source-to-self or source-to-target
        evaluations, find 'where' attributes automatically.
    """

    if context is None:
        context = {}

    from pytools.obj_array import is_obj_array, make_obj_array
    if not isinstance(places, GeometryCollection):
        places = GeometryCollection(places, auto_where=auto_where)
    exprs = _prepare_expr(places, exprs)

    if not is_obj_array(exprs):
        exprs = make_obj_array([exprs])
    try:
        input_exprs = list(input_exprs)
    except TypeError:
        # not iterable, wrap in a list
        input_exprs = [input_exprs]

    domains = _prepare_domains(len(input_exprs), places, domains,
                               places.auto_source)

    from pytential.symbolic.matrix import MatrixBuilder, is_zero
    nblock_rows = len(exprs)
    nblock_columns = len(input_exprs)
    blocks = np.zeros((nblock_rows, nblock_columns), dtype=np.object)

    dtypes = []
    for ibcol in range(nblock_columns):
        mbuilder = MatrixBuilder(
            queue,
            dep_expr=input_exprs[ibcol],
            other_dep_exprs=(input_exprs[:ibcol] + input_exprs[ibcol + 1:]),
            dep_source=places.get_geometry(domains[ibcol]),
            dep_discr=places.get_discretization(domains[ibcol]),
            places=places,
            context=context)

        for ibrow in range(nblock_rows):
            block = mbuilder(exprs[ibrow])
            assert is_zero(block) or isinstance(block, np.ndarray)

            blocks[ibrow, ibcol] = block
            if isinstance(block, np.ndarray):
                dtypes.append(block.dtype)

    return cl.array.to_device(queue, _bmat(blocks, dtypes))
Esempio n. 48
0
def build_matrix(queue, places, exprs, input_exprs, domains=None,
        auto_where=None, context=None):
    """
    :arg queue: a :class:`pyopencl.CommandQueue`.
    :arg places: a :class:`pytential.symbolic.execution.GeometryCollection`.
        Alternatively, any list or mapping that is a valid argument for its
        constructor can also be used.
    :arg exprs: an array of expressions corresponding to the output block
        rows of the matrix. May also be a single expression.
    :arg input_exprs: an array of expressions corresponding to the
        input block columns of the matrix. May also be a single expression.
    :arg domains: a list of discretization identifiers (see 'places') or
        *None* values indicating the domains on which each component of the
        solution vector lives.  *None* values indicate that the component
        is a scalar.  If *None*, *auto_where* or, if it is not provided,
        :class:`~pytential.symbolic.primitives.DEFAULT_SOURCE` is required
        to be a key in :attr:`places`.
    :arg auto_where: For simple source-to-self or source-to-target
        evaluations, find 'where' attributes automatically.
    """

    if context is None:
        context = {}

    from pytools.obj_array import is_obj_array, make_obj_array
    if not isinstance(places, GeometryCollection):
        places = GeometryCollection(places, auto_where=auto_where)
    exprs = _prepare_expr(places, exprs)

    if not is_obj_array(exprs):
        exprs = make_obj_array([exprs])
    try:
        input_exprs = list(input_exprs)
    except TypeError:
        # not iterable, wrap in a list
        input_exprs = [input_exprs]

    domains = _prepare_domains(len(input_exprs), places, domains,
                               places._default_source_place)

    from pytential.symbolic.matrix import MatrixBuilder, is_zero
    nblock_rows = len(exprs)
    nblock_columns = len(input_exprs)
    blocks = np.zeros((nblock_rows, nblock_columns), dtype=np.object)

    dtypes = []
    for ibcol in range(nblock_columns):
        mbuilder = MatrixBuilder(
                queue,
                dep_expr=input_exprs[ibcol],
                other_dep_exprs=(input_exprs[:ibcol]
                                 + input_exprs[ibcol + 1:]),
                dep_source=places[domains[ibcol]],
                dep_discr=places.get_discretization(domains[ibcol]),
                places=places,
                context=context)

        for ibrow in range(nblock_rows):
            block = mbuilder(exprs[ibrow])
            assert is_zero(block) or isinstance(block, np.ndarray)

            blocks[ibrow, ibcol] = block
            if isinstance(block, np.ndarray):
                dtypes.append(block.dtype)

    return cl.array.to_device(queue, _bmat(blocks, dtypes))