Example #1
0
            def map_common_subexpression(self, expr):
                # Here we need to decide whether this CSE should be turned into
                # a flux CSE or not. This is a good idea if the transformed
                # expression only contains "bare" volume or boundary
                # expressions.  However, as soon as an operator is applied
                # somewhere in the subexpression, the CSE should not be touched
                # in order to avoid redundant evaluation of that operator.
                #
                # Observe that at the time of this writing (Feb 2010), the only
                # operators that may occur in boundary expressions are
                # quadrature-related.

                has_expensive_operators = \
                        self.expensive_bdry_op_detector(expr.child)

                if has_expensive_operators:
                    return FieldComponent(self.register_boundary_expr(expr),
                                          is_interior=False)
                else:
                    return IdentityMapper.map_common_subexpression(self, expr)
Example #2
0
            def map_common_subexpression(self, expr):
                # Here we need to decide whether this CSE should be turned into
                # a flux CSE or not. This is a good idea if the transformed
                # expression only contains "bare" volume or boundary
                # expressions.  However, as soon as an operator is applied
                # somewhere in the subexpression, the CSE should not be touched
                # in order to avoid redundant evaluation of that operator.
                #
                # Observe that at the time of this writing (Feb 2010), the only
                # operators that may occur in boundary expressions are
                # quadrature-related.

                has_expensive_operators = \
                        self.expensive_bdry_op_detector(expr.child)

                if has_expensive_operators:
                    return FieldComponent(
                            self.register_boundary_expr(expr),
                            is_interior=False)
                else:
                    return IdentityMapper.map_common_subexpression(self, expr)
Example #3
0
    def map_operator_binding(self, expr):
        from hedge.optemplate.operators import FluxOperatorBase
        from hedge.optemplate.primitives import BoundaryPair
        from hedge.flux import FluxSubstitutionMapper, FieldComponent

        if not (isinstance(expr.op, FluxOperatorBase)
                and isinstance(expr.field, BoundaryPair)):
            return IdentityMapper.map_operator_binding(self, expr)

        bpair = expr.field
        vol_field = bpair.field
        bdry_field = bpair.bfield
        flux = expr.op.flux

        bdry_dependencies = DependencyMapper(
                    include_calls="descend_args",
                    include_operator_bindings=True)(bdry_field)

        vol_dependencies = DependencyMapper(
                include_operator_bindings=True)(vol_field)

        vol_bdry_intersection = bdry_dependencies & vol_dependencies
        if vol_bdry_intersection:
            raise RuntimeError("Variables are being used as both "
                    "boundary and volume quantities: %s"
                    % ", ".join(str(v) for v in vol_bdry_intersection))

        # Step 1: Find maximal flux-evaluable subexpression of boundary field
        # in given BoundaryPair.

        class MaxBoundaryFluxEvaluableExpressionFinder(
                IdentityMapper, OperatorReducerMixin):

            def __init__(self, vol_expr_list, expensive_bdry_op_detector):
                self.vol_expr_list = vol_expr_list
                self.vol_expr_to_idx = dict((vol_expr, idx)
                        for idx, vol_expr in enumerate(vol_expr_list))

                self.bdry_expr_list = []
                self.bdry_expr_to_idx = {}

                self.expensive_bdry_op_detector = expensive_bdry_op_detector

            # {{{ expression registration
            def register_boundary_expr(self, expr):
                try:
                    return self.bdry_expr_to_idx[expr]
                except KeyError:
                    idx = len(self.bdry_expr_to_idx)
                    self.bdry_expr_to_idx[expr] = idx
                    self.bdry_expr_list.append(expr)
                    return idx

            def register_volume_expr(self, expr):
                try:
                    return self.vol_expr_to_idx[expr]
                except KeyError:
                    idx = len(self.vol_expr_to_idx)
                    self.vol_expr_to_idx[expr] = idx
                    self.vol_expr_list.append(expr)
                    return idx

            # }}}

            # {{{ map_xxx routines

            @memoize_method
            def map_common_subexpression(self, expr):
                # Here we need to decide whether this CSE should be turned into
                # a flux CSE or not. This is a good idea if the transformed
                # expression only contains "bare" volume or boundary
                # expressions.  However, as soon as an operator is applied
                # somewhere in the subexpression, the CSE should not be touched
                # in order to avoid redundant evaluation of that operator.
                #
                # Observe that at the time of this writing (Feb 2010), the only
                # operators that may occur in boundary expressions are
                # quadrature-related.

                has_expensive_operators = \
                        self.expensive_bdry_op_detector(expr.child)

                if has_expensive_operators:
                    return FieldComponent(
                            self.register_boundary_expr(expr),
                            is_interior=False)
                else:
                    return IdentityMapper.map_common_subexpression(self, expr)

            def map_normal(self, expr):
                raise RuntimeError("Your operator template contains a flux normal. "
                        "You may find this confusing, but you can't do that. "
                        "It turns out that you need to use "
                        "hedge.optemplate.make_normal() for normals in boundary "
                        "terms of operator templates.")

            def map_normal_component(self, expr):
                if expr.boundary_tag != bpair.tag:
                    raise RuntimeError("BoundaryNormalComponent and BoundaryPair "
                            "do not agree about boundary tag: %s vs %s"
                            % (expr.boundary_tag, bpair.tag))

                from hedge.flux import Normal
                return Normal(expr.axis)

            def map_variable(self, expr):
                return FieldComponent(
                        self.register_boundary_expr(expr),
                        is_interior=False)

            map_subscript = map_variable

            def map_operator_binding(self, expr):
                from hedge.optemplate import (BoundarizeOperator,
                        FluxExchangeOperator,
                        QuadratureGridUpsampler,
                        QuadratureBoundaryGridUpsampler)

                if isinstance(expr.op, BoundarizeOperator):
                    if expr.op.tag != bpair.tag:
                        raise RuntimeError("BoundarizeOperator and BoundaryPair "
                                "do not agree about boundary tag: %s vs %s"
                                % (expr.op.tag, bpair.tag))

                    return FieldComponent(
                            self.register_volume_expr(expr.field),
                            is_interior=True)

                elif isinstance(expr.op, FluxExchangeOperator):
                    from hedge.mesh import TAG_RANK_BOUNDARY
                    op_tag = TAG_RANK_BOUNDARY(expr.op.rank)
                    if bpair.tag != op_tag:
                        raise RuntimeError("BoundarizeOperator and FluxExchangeOperator "
                                "do not agree about boundary tag: %s vs %s"
                                % (op_tag, bpair.tag))
                    return FieldComponent(
                            self.register_boundary_expr(expr),
                            is_interior=False)

                elif isinstance(expr.op, QuadratureBoundaryGridUpsampler):
                    if bpair.tag != expr.op.boundary_tag:
                        raise RuntimeError("BoundarizeOperator "
                                "and QuadratureBoundaryGridUpsampler "
                                "do not agree about boundary tag: %s vs %s"
                                % (expr.op.boundary_tag, bpair.tag))
                    return FieldComponent(
                            self.register_boundary_expr(expr),
                            is_interior=False)

                elif isinstance(expr.op, QuadratureGridUpsampler):
                    # We're invoked before operator specialization, so we may
                    # see these instead of QuadratureBoundaryGridUpsampler.
                    return FieldComponent(
                            self.register_boundary_expr(expr),
                            is_interior=False)

                else:
                    raise RuntimeError("Found '%s' in a boundary term. "
                            "To the best of my knowledge, no hedge operator applies "
                            "directly to boundary data, so this is likely in error."
                            % expr.op)

            def map_flux_exchange(self, expr):
                return FieldComponent(
                        self.register_boundary_expr(expr),
                        is_interior=False)
            # }}}

        from hedge.tools import is_obj_array
        if not is_obj_array(vol_field):
            vol_field = [vol_field]

        mbfeef = MaxBoundaryFluxEvaluableExpressionFinder(list(vol_field),
                self.expensive_bdry_op_detector)
        #from hedge.optemplate.tools import pretty_print_optemplate
        #print pretty_print_optemplate(bdry_field)
        #raw_input("YO")
        new_bdry_field = mbfeef(bdry_field)

        # Step II: Substitute the new_bdry_field into the flux.
        def sub_bdry_into_flux(expr):
            if isinstance(expr, FieldComponent) and not expr.is_interior:
                if expr.index == 0 and not is_obj_array(bdry_field):
                    return new_bdry_field
                else:
                    return new_bdry_field[expr.index]
            else:
                return None

        new_flux = FluxSubstitutionMapper(sub_bdry_into_flux)(flux)

        from hedge.tools import is_zero, make_obj_array
        if is_zero(new_flux):
            return 0
        else:
            return type(expr.op)(new_flux, *expr.op.__getinitargs__()[1:])(
                    BoundaryPair(
                        make_obj_array([self.rec(e) for e in mbfeef.vol_expr_list]),
                        make_obj_array([self.rec(e) for e in mbfeef.bdry_expr_list]),
                        bpair.tag))
Example #4
0
    def map_operator_binding(self, expr):
        from hedge.optemplate.operators import FluxOperatorBase
        from hedge.optemplate.primitives import BoundaryPair
        from hedge.flux import FluxSubstitutionMapper, FieldComponent

        if not (isinstance(expr.op, FluxOperatorBase)
                and isinstance(expr.field, BoundaryPair)):
            return IdentityMapper.map_operator_binding(self, expr)

        bpair = expr.field
        vol_field = bpair.field
        bdry_field = bpair.bfield
        flux = expr.op.flux

        bdry_dependencies = DependencyMapper(
            include_calls="descend_args",
            include_operator_bindings=True)(bdry_field)

        vol_dependencies = DependencyMapper(
            include_operator_bindings=True)(vol_field)

        vol_bdry_intersection = bdry_dependencies & vol_dependencies
        if vol_bdry_intersection:
            raise RuntimeError(
                "Variables are being used as both "
                "boundary and volume quantities: %s" %
                ", ".join(str(v) for v in vol_bdry_intersection))

        # Step 1: Find maximal flux-evaluable subexpression of boundary field
        # in given BoundaryPair.

        class MaxBoundaryFluxEvaluableExpressionFinder(IdentityMapper,
                                                       OperatorReducerMixin):
            def __init__(self, vol_expr_list, expensive_bdry_op_detector):
                self.vol_expr_list = vol_expr_list
                self.vol_expr_to_idx = dict(
                    (vol_expr, idx)
                    for idx, vol_expr in enumerate(vol_expr_list))

                self.bdry_expr_list = []
                self.bdry_expr_to_idx = {}

                self.expensive_bdry_op_detector = expensive_bdry_op_detector

            # {{{ expression registration
            def register_boundary_expr(self, expr):
                try:
                    return self.bdry_expr_to_idx[expr]
                except KeyError:
                    idx = len(self.bdry_expr_to_idx)
                    self.bdry_expr_to_idx[expr] = idx
                    self.bdry_expr_list.append(expr)
                    return idx

            def register_volume_expr(self, expr):
                try:
                    return self.vol_expr_to_idx[expr]
                except KeyError:
                    idx = len(self.vol_expr_to_idx)
                    self.vol_expr_to_idx[expr] = idx
                    self.vol_expr_list.append(expr)
                    return idx

            # }}}

            # {{{ map_xxx routines

            @memoize_method
            def map_common_subexpression(self, expr):
                # Here we need to decide whether this CSE should be turned into
                # a flux CSE or not. This is a good idea if the transformed
                # expression only contains "bare" volume or boundary
                # expressions.  However, as soon as an operator is applied
                # somewhere in the subexpression, the CSE should not be touched
                # in order to avoid redundant evaluation of that operator.
                #
                # Observe that at the time of this writing (Feb 2010), the only
                # operators that may occur in boundary expressions are
                # quadrature-related.

                has_expensive_operators = \
                        self.expensive_bdry_op_detector(expr.child)

                if has_expensive_operators:
                    return FieldComponent(self.register_boundary_expr(expr),
                                          is_interior=False)
                else:
                    return IdentityMapper.map_common_subexpression(self, expr)

            def map_normal(self, expr):
                raise RuntimeError(
                    "Your operator template contains a flux normal. "
                    "You may find this confusing, but you can't do that. "
                    "It turns out that you need to use "
                    "hedge.optemplate.make_normal() for normals in boundary "
                    "terms of operator templates.")

            def map_normal_component(self, expr):
                if expr.boundary_tag != bpair.tag:
                    raise RuntimeError(
                        "BoundaryNormalComponent and BoundaryPair "
                        "do not agree about boundary tag: %s vs %s" %
                        (expr.boundary_tag, bpair.tag))

                from hedge.flux import Normal
                return Normal(expr.axis)

            def map_variable(self, expr):
                return FieldComponent(self.register_boundary_expr(expr),
                                      is_interior=False)

            map_subscript = map_variable

            def map_operator_binding(self, expr):
                from hedge.optemplate import (BoundarizeOperator,
                                              FluxExchangeOperator,
                                              QuadratureGridUpsampler,
                                              QuadratureBoundaryGridUpsampler)

                if isinstance(expr.op, BoundarizeOperator):
                    if expr.op.tag != bpair.tag:
                        raise RuntimeError(
                            "BoundarizeOperator and BoundaryPair "
                            "do not agree about boundary tag: %s vs %s" %
                            (expr.op.tag, bpair.tag))

                    return FieldComponent(self.register_volume_expr(
                        expr.field),
                                          is_interior=True)

                elif isinstance(expr.op, FluxExchangeOperator):
                    from hedge.mesh import TAG_RANK_BOUNDARY
                    op_tag = TAG_RANK_BOUNDARY(expr.op.rank)
                    if bpair.tag != op_tag:
                        raise RuntimeError(
                            "BoundarizeOperator and "
                            "FluxExchangeOperator do not agree about "
                            "boundary tag: %s vs %s" % (op_tag, bpair.tag))
                    return FieldComponent(self.register_boundary_expr(expr),
                                          is_interior=False)

                elif isinstance(expr.op, QuadratureBoundaryGridUpsampler):
                    if bpair.tag != expr.op.boundary_tag:
                        raise RuntimeError(
                            "BoundarizeOperator "
                            "and QuadratureBoundaryGridUpsampler "
                            "do not agree about boundary tag: %s vs %s" %
                            (expr.op.boundary_tag, bpair.tag))
                    return FieldComponent(self.register_boundary_expr(expr),
                                          is_interior=False)

                elif isinstance(expr.op, QuadratureGridUpsampler):
                    # We're invoked before operator specialization, so we may
                    # see these instead of QuadratureBoundaryGridUpsampler.
                    return FieldComponent(self.register_boundary_expr(expr),
                                          is_interior=False)

                else:
                    raise RuntimeError(
                        "Found '%s' in a boundary term. "
                        "To the best of my knowledge, no hedge operator applies "
                        "directly to boundary data, so this is likely in error."
                        % expr.op)

            def map_flux_exchange(self, expr):
                return FieldComponent(self.register_boundary_expr(expr),
                                      is_interior=False)

            # }}}

        from hedge.tools import is_obj_array
        if not is_obj_array(vol_field):
            vol_field = [vol_field]

        mbfeef = MaxBoundaryFluxEvaluableExpressionFinder(
            list(vol_field), self.expensive_bdry_op_detector)
        #from hedge.optemplate.tools import pretty
        #print pretty(bdry_field)
        #raw_input("YO")
        new_bdry_field = mbfeef(bdry_field)

        # Step II: Substitute the new_bdry_field into the flux.
        def sub_bdry_into_flux(expr):
            if isinstance(expr, FieldComponent) and not expr.is_interior:
                if expr.index == 0 and not is_obj_array(bdry_field):
                    return new_bdry_field
                else:
                    return new_bdry_field[expr.index]
            else:
                return None

        new_flux = FluxSubstitutionMapper(sub_bdry_into_flux)(flux)

        from hedge.tools import is_zero, make_obj_array
        if is_zero(new_flux):
            return 0
        else:
            return type(expr.op)(new_flux, *expr.op.__getinitargs__()[1:])(
                BoundaryPair(
                    make_obj_array([self.rec(e)
                                    for e in mbfeef.vol_expr_list]),
                    make_obj_array(
                        [self.rec(e) for e in mbfeef.bdry_expr_list]),
                    bpair.tag))