def __init__(self, module, F, M, u):
        """
        *Arguments*

            module (Python module)
               The module to use for specific form manipulations
               (typically ufl or dolfin)

            F (tuple or Form)
               tuple of (bilinear, linear) forms or linear form

            M (Form)
               functional or linear form

            u (Coefficient)
              The coefficient considered as the unknown.
        """
        # Store module
        self.module = module

        # Store solution Coefficient/Function
        self.u = u

        # Extract the lhs (bilinear form), rhs (linear form), goal
        # (functional), weak residual (linear form)
        linear_case = (isinstance(F, (tuple, list)) and len(F) == 2)
        if linear_case:
            self.lhs, self.rhs = F
            try:
                self.goal = action(M, u)
            except:
                self.goal = M  # Allow functionals as input as well
            self.weak_residual = self.rhs - action(self.lhs, u)
        else:
            self.lhs = self.module.derivative(F, u)
            self.rhs = F
            self.goal = M
            self.weak_residual = -F

        # At least check that final forms have correct rank
        assert (len(extract_arguments(self.lhs)) == 2)
        assert (len(extract_arguments(self.rhs)) == 1)
        assert (len(extract_arguments(self.goal)) == 0)
        assert (len(extract_arguments(self.weak_residual)) == 1)

        # Store map from identifiers to names for forms and generated
        # coefficients
        self.ec_names = {}

        # Use predefined names for the forms in the primal problem
        self.ec_names[id(self.lhs)] = "lhs"
        self.ec_names[id(self.rhs)] = "rhs"
        self.ec_names[id(self.goal)] = "goal"

        # Initialize other required data
        self.initialize_data()
Beispiel #2
0
def compute_form_with_arity(form, arity, arguments=None):
    """Compute parts of form of given arity."""

    # Extract all arguments in form
    if arguments is None:
        arguments = extract_arguments(form)

    if len(arguments) < arity:
        warning("Form has no parts with arity %d." % arity)
        return 0 * form

    # Assuming that the form is not a sum of terms
    # that depend on different arguments, e.g. (u+v)*dx
    # would result in just v*dx. But that doesn't make
    # any sense anyway.
    sub_arguments = set(arguments[:arity])
    pe = PartExtracter(sub_arguments)

    def _transform(e):
        e, provides = pe.visit(e)
        if provides == sub_arguments:
            return e
        return Zero()

    res = transform_integrands(form, _transform)
    return res
Beispiel #3
0
def compute_form_action(form, coefficient):
    """Compute the action of a form on a Coefficient.

    This works simply by replacing the last Argument
    with a Coefficient on the same function space (element).
    The form returned will thus have one Argument less
    and one additional Coefficient at the end if no
    Coefficient has been provided.
    """
    # TODO: Check whatever makes sense for coefficient

    # Extract all arguments
    arguments = extract_arguments(form)

    # Pick last argument (will be replaced)
    u = arguments[-1]

    e = u.element()
    if coefficient is None:
        coefficient = Coefficient(e)
    else:
        #ufl_assert(coefficient.element() == e, \
        if coefficient.element() != e:
            debug(
                "Computing action of form on a coefficient in a different element space."
            )
    return replace(form, {u: coefficient})
def compute_form_action(form, coefficient):
    """Compute the action of a form on a Coefficient.

    This works simply by replacing the last Argument
    with a Coefficient on the same function space (element).
    The form returned will thus have one Argument less
    and one additional Coefficient at the end if no
    Coefficient has been provided.
    """
    # TODO: Check whatever makes sense for coefficient

    # Extract all arguments
    arguments = extract_arguments(form)

    # Pick last argument (will be replaced)
    u = arguments[-1]

    e = u.element()
    if coefficient is None:
        coefficient = Coefficient(e)
    else:
        #ufl_assert(coefficient.element() == e, \
        if coefficient.element() != e:
            debug("Computing action of form on a coefficient in a different element space.")
    return replace(form, { u: coefficient })
Beispiel #5
0
def compute_energy_norm(form, coefficient):
    """Compute the a-norm of a Coefficient given a form a.

    This works simply by replacing the two Arguments
    with a Coefficient on the same function space (element).
    The Form returned will thus be a functional with no
    Arguments, and one additional Coefficient at the
    end if no coefficient has been provided.
    """
    arguments = extract_arguments(form)
    ufl_assert(len(arguments) == 2, "Expecting bilinear form.")
    v, u = arguments
    e = u.element()
    e2 = v.element()
    ufl_assert(
        e == e2,
        "Expecting equal finite elements for test and trial functions, got '%s' and '%s'."
        % (str(e), str(e2)))
    if coefficient is None:
        coefficient = Coefficient(e)
    else:
        ufl_assert(coefficient.element() == e, \
            "Trying to compute action of form on a "\
            "coefficient in an incompatible element space.")
    return replace(form, {u: coefficient, v: coefficient})
    def initialize_data(self):
        """
        Extract required objects for defining error control
        forms. This will be stored, reused and in particular named.
        """
        # Developer's note: The UFL-FFC-DOLFIN--PyDOLFIN toolchain for
        # error control is quite fine-tuned. In particular, the order
        # of coefficients in forms is (and almost must be) used for
        # their assignment. This means that the order in which these
        # coefficients are defined matters and should be considered
        # fixed.

        from ufl import FiniteElement, Coefficient
        from ufl.algorithms.elementtransformations import tear, increase_order

        # Primal trial element space
        self._V = self.u.element()

        # Primal test space == Dual trial space
        Vhat = extract_arguments(self.weak_residual)[0].element()

        # Discontinuous version of primal trial element space
        self._dV = tear(self._V)

        # Extract cell and geometric dimension
        cell = self._V.cell()
        gdim = cell.geometric_dimension()

        # Coefficient representing improved dual
        E = increase_order(Vhat)
        self._Ez_h = Coefficient(E)
        self.ec_names[id(self._Ez_h)] = "__improved_dual"

        # Coefficient representing cell bubble function
        B = FiniteElement("B", cell, gdim + 1)
        self._b_T = Coefficient(B)
        self.ec_names[id(self._b_T)] = "__cell_bubble"

        # Coefficient representing strong cell residual
        self._R_T = Coefficient(self._dV)
        self.ec_names[id(self._R_T)] = "__cell_residual"

        # Coefficient representing cell cone function
        C = FiniteElement("DG", cell, gdim)
        self._b_e = Coefficient(C)
        self.ec_names[id(self._b_e)] = "__cell_cone"

        # Coefficient representing strong facet residual
        self._R_dT = Coefficient(self._dV)
        self.ec_names[id(self._R_dT)] = "__facet_residual"

        # Define discrete dual on primal test space
        self._z_h = Coefficient(Vhat)
        self.ec_names[id(self._z_h)] = "__discrete_dual_solution"

        # Piecewise constants for assembling indicators
        self._DG0 = FiniteElement("DG", cell, 0)
Beispiel #7
0
    def initialize_data(self):
        """
        Extract required objects for defining error control
        forms. This will be stored and reused.
        """
        # Developer's note: The UFL-FFC-DOLFIN--PyDOLFIN toolchain for
        # error control is quite fine-tuned. In particular, the order
        # of coefficients in forms is (and almost must be) used for
        # their assignment. This means that the order in which these
        # coefficients are defined matters and should be considered
        # fixed.

        # Primal trial element space
        self._V = self.u.function_space()

        # Primal test space == Dual trial space
        Vhat = extract_arguments(self.weak_residual)[0].function_space()

        # Discontinuous version of primal trial element space
        self._dV = tear(self._V)

        # Extract cell and geometric dimension
        mesh = self._V.mesh()
        dim = mesh.topology().dim()

        # Function representing improved dual
        E = increase_order(Vhat)
        self._Ez_h = Function(E)

        # Function representing cell bubble function
        B = FunctionSpace(mesh, "B", dim + 1)
        self._b_T = Function(B)
        self._b_T.vector()[:] = 1.0

        # Function representing strong cell residual
        self._R_T = Function(self._dV)

        # Function representing cell cone function
        C = FunctionSpace(mesh, "DG", dim)
        self._b_e = Function(C)

        # Function representing strong facet residual
        self._R_dT = Function(self._dV)

        # Function for discrete dual on primal test space
        self._z_h = Function(Vhat)

        # Piecewise constants for assembling indicators
        self._DG0 = FunctionSpace(mesh, "DG", 0)
Beispiel #8
0
def entity_avg(integrand, measure, argument_multiindices):
    arguments = extract_arguments(integrand)
    if len(arguments) == 1:
        a, = arguments
        integrand = ufl.replace(integrand, {a: ufl.Argument(a.function_space(),
                                                            number=0,
                                                            part=a.part())})
        argument_multiindices = (argument_multiindices[a.number()], )

    degree = estimate_total_polynomial_degree(integrand)
    form = integrand * measure
    fd = compute_form_data(form, do_estimate_degrees=False,
                           do_apply_function_pullbacks=False)
    itg_data, = fd.integral_data
    integral, = itg_data.integrals
    integrand = integral.integrand()
    return integrand, degree, argument_multiindices
def compute_form_arities(form):
    """Return set of arities of terms present in form."""
    #ufl_assert(form.is_preprocessed(), "Assuming a preprocessed form.")

    # Extract all arguments present in form
    arguments = extract_arguments(form)

    arities = set()
    for arity in range(len(arguments)+1):

        # Compute parts with arity "arity"
        parts = compute_form_with_arity(form, arity, arguments)

        # Register arity if "parts" does not vanish
        if parts and parts.integrals():
            arities.add(arity)

    return arities
Beispiel #10
0
def compute_form_arities(form):
    """Return set of arities of terms present in form."""
    #ufl_assert(form.is_preprocessed(), "Assuming a preprocessed form.")

    # Extract all arguments present in form
    arguments = extract_arguments(form)

    arities = set()
    for arity in range(len(arguments) + 1):

        # Compute parts with arity "arity"
        parts = compute_form_with_arity(form, arity, arguments)

        # Register arity if "parts" does not vanish
        if parts and parts.integrals():
            arities.add(arity)

    return arities
    def cell_residual(self):
        """
        Generate and return (bilinear, linear) forms defining linear
        variational problem for the strong cell residual
        """
        # Define trial and test functions for the cell residuals on
        # discontinuous version of primal trial space
        R_T = self.module.TrialFunction(self._dV)
        v = self.module.TestFunction(self._dV)

        # Extract original test function in the weak residual
        v_h = extract_arguments(self.weak_residual)[0]

        # Define forms defining linear variational problem for cell
        # residual
        v_T = self._b_T * v
        a_R_T = inner(v_T, R_T) * dx()
        L_R_T = replace(self.weak_residual, {v_h: v_T})

        return (a_R_T, L_R_T)
Beispiel #12
0
def adjoint(form, reordered_arguments=None):
    """UFL form operator:
    Given a combined bilinear form, compute the adjoint form by
    changing the ordering (count) of the test and trial functions.

    By default, new Argument objects will be created with
    opposite ordering. However, if the adjoint form is to
    be added to other forms later, their arguments must match.
    In that case, the user must provide a tuple reordered_arguments=(u2,v2).
    """

    # ufl.adjoint creates new Arguments if no reordered_arguments is
    # given.  To avoid that, always pass reordered_arguments with
    # firedrake.Argument objects.
    if reordered_arguments is None:
        v, u = extract_arguments(form)
        reordered_arguments = (Argument(u.element(), u.function_space(),
                                        count=v.count()),
                               Argument(v.element(), v.function_space(),
                                        count=u.count()))
    return ufl.adjoint(form, reordered_arguments)
def form_info(form):
    ufl_assert(isinstance(form, Form), "Expecting a Form.")

    bf = extract_arguments(form)
    cf = extract_coefficients(form)

    ci = form.integrals(Measure.CELL)
    ei = form.integrals(Measure.EXTERIOR_FACET)
    ii = form.integrals(Measure.INTERIOR_FACET)
    pi = form.integrals(Measure.POINT)
    mi = form.integrals(Measure.MACRO_CELL)

    s  = "Form info:\n"
    s += "  rank:                          %d\n" % len(bf)
    s += "  num_coefficients:              %d\n" % len(cf)
    s += "  num_cell_integrals:            %d\n" % len(ci)
    s += "  num_exterior_facet_integrals:  %d\n" % len(ei)
    s += "  num_interior_facet_integrals:  %d\n" % len(ii)
    s += "  num_point_integrals:           %d\n" % len(pi)
    s += "  num_macro_cell_integrals:      %d\n" % len(mi)

    for f in cf:
        if f._name:
            s += "\n"
            s += "  Coefficient %d is named '%s'" % (f._count, f._name)
    s += "\n"

    for itg in ci:
        s += "\n"
        s += integral_info(itg)
    for itg in ei:
        s += "\n"
        s += integral_info(itg)
    for itg in ii:
        s += "\n"
        s += integral_info(itg)
    for itg in mi:
        s += "\n"
        s += integral_info(itg)
    return s
def form_info(form):
    ufl_assert(isinstance(form, Form), "Expecting a Form.")

    bf = extract_arguments(form)
    cf = extract_coefficients(form)

    ci = form.integrals(Measure.CELL)
    ei = form.integrals(Measure.EXTERIOR_FACET)
    ii = form.integrals(Measure.INTERIOR_FACET)
    pi = form.integrals(Measure.POINT)
    mi = form.integrals(Measure.MACRO_CELL)

    s = "Form info:\n"
    s += "  rank:                          %d\n" % len(bf)
    s += "  num_coefficients:              %d\n" % len(cf)
    s += "  num_cell_integrals:            %d\n" % len(ci)
    s += "  num_exterior_facet_integrals:  %d\n" % len(ei)
    s += "  num_interior_facet_integrals:  %d\n" % len(ii)
    s += "  num_point_integrals:           %d\n" % len(pi)
    s += "  num_macro_cell_integrals:      %d\n" % len(mi)

    for f in cf:
        if f._name:
            s += "\n"
            s += "  Coefficient %d is named '%s'" % (f._count, f._name)
    s += "\n"

    for itg in ci:
        s += "\n"
        s += integral_info(itg)
    for itg in ei:
        s += "\n"
        s += integral_info(itg)
    for itg in ii:
        s += "\n"
        s += integral_info(itg)
    for itg in mi:
        s += "\n"
        s += integral_info(itg)
    return s
def compute_energy_norm(form, coefficient):
    """Compute the a-norm of a Coefficient given a form a.

    This works simply by replacing the two Arguments
    with a Coefficient on the same function space (element).
    The Form returned will thus be a functional with no
    Arguments, and one additional Coefficient at the
    end if no coefficient has been provided.
    """
    arguments = extract_arguments(form)
    ufl_assert(len(arguments) == 2, "Expecting bilinear form.")
    v, u = arguments
    e = u.element()
    e2 = v.element()
    ufl_assert(e == e2, "Expecting equal finite elements for test and trial functions, got '%s' and '%s'." % (str(e), str(e2)))
    if coefficient is None:
        coefficient = Coefficient(e)
    else:
        ufl_assert(coefficient.element() == e, \
            "Trying to compute action of form on a "\
            "coefficient in an incompatible element space.")
    return replace(form, { u: coefficient, v: coefficient })
def compute_form_adjoint(form, reordered_arguments=None):
    """Compute the adjoint of a bilinear form.

    This works simply by changing the ordering (count) of the two arguments.
    """
    arguments = extract_arguments(form)
    ufl_assert(len(arguments) == 2, "Expecting bilinear form.")

    v, u = arguments
    ufl_assert(v.count() < u.count(), "Mistaken assumption in code!")

    if reordered_arguments is None:
        reordered_arguments = (Argument(u.element()), Argument(v.element()))
    reordered_u, reordered_v = reordered_arguments
    ufl_assert(reordered_u.count() < reordered_v.count(),
               "Ordering of new arguments is the same as the old arguments!")
    ufl_assert(reordered_u.element() == u.element(),
               "Element mismatch between new and old arguments (trial functions).")
    ufl_assert(reordered_v.element() == v.element(),
               "Element mismatch between new and old arguments (test functions).")

    return replace(form, {v: reordered_v, u: reordered_u})
    def facet_residual(self):
        """
        Generate and return (bilinear, linear) forms defining linear
        variational problem for the strong facet residual(s)
        """
        # Define trial and test functions for the facet residuals on
        # discontinuous version of primal trial space
        R_e = self.module.TrialFunction(self._dV)
        v = self.module.TestFunction(self._dV)

        # Extract original test function in the weak residual
        v_h = extract_arguments(self.weak_residual)[0]

        # Define forms defining linear variational problem for facet
        # residual
        v_e = self._b_e * v
        a_R_dT = (
            (inner(v_e('+'), R_e('+')) + inner(v_e('-'), R_e('-'))) * dS() +
            inner(v_e, R_e) * ds())
        L_R_dT = (replace(self.weak_residual, {v_h: v_e}) -
                  inner(v_e, self._R_T) * dx())

        return (a_R_dT, L_R_dT)
Beispiel #18
0
def adjoint(form, reordered_arguments=None):
    """UFL form operator:
    Given a combined bilinear form, compute the adjoint form by
    changing the ordering (number) of the test and trial functions.

    By default, new Argument objects will be created with
    opposite ordering. However, if the adjoint form is to
    be added to other forms later, their arguments must match.
    In that case, the user must provide a tuple reordered_arguments=(u2,v2).
    """

    # ufl.adjoint creates new Arguments if no reordered_arguments is
    # given.  To avoid that, always pass reordered_arguments with
    # firedrake.Argument objects.
    if reordered_arguments is None:
        v, u = extract_arguments(form)
        reordered_arguments = (Argument(u.function_space(),
                                        number=v.number(),
                                        part=v.part()),
                               Argument(v.function_space(),
                                        number=u.number(),
                                        part=u.part()))
    return ufl.adjoint(form, reordered_arguments)
Beispiel #19
0
def compute_form_adjoint(form, reordered_arguments=None):
    """Compute the adjoint of a bilinear form.

    This works simply by changing the ordering (count) of the two arguments.
    """
    arguments = extract_arguments(form)
    ufl_assert(len(arguments) == 2, "Expecting bilinear form.")

    v, u = arguments
    ufl_assert(v.count() < u.count(), "Mistaken assumption in code!")

    if reordered_arguments is None:
        reordered_arguments = (Argument(u.element()), Argument(v.element()))
    reordered_u, reordered_v = reordered_arguments
    ufl_assert(reordered_u.count() < reordered_v.count(),
               "Ordering of new arguments is the same as the old arguments!")
    ufl_assert(
        reordered_u.element() == u.element(),
        "Element mismatch between new and old arguments (trial functions).")
    ufl_assert(
        reordered_v.element() == v.element(),
        "Element mismatch between new and old arguments (test functions).")

    return replace(form, {v: reordered_v, u: reordered_u})
def compute_form_with_arity(form, arity, arguments=None):
    """Compute parts of form of given arity."""

    # Extract all arguments in form
    if arguments is None:
        arguments = extract_arguments(form)

    if len(arguments) < arity:
        warning("Form has no parts with arity %d." % arity)
        return 0*form

    # Assuming that the form is not a sum of terms
    # that depend on different arguments, e.g. (u+v)*dx
    # would result in just v*dx. But that doesn't make
    # any sense anyway.
    sub_arguments = set(arguments[:arity])
    pe = PartExtracter(sub_arguments)
    def _transform(e):
        e, provides = pe.visit(e)
        if provides == sub_arguments:
            return e
        return Zero()
    res = transform_integrands(form, _transform)
    return res
Beispiel #21
0
def prepare_input_arguments(forms, object_names, reserved_objects):
    """
    Extract required input arguments to UFLErrorControlGenerator.

    *Arguments*

        forms (tuple)
            Three (linear case) or two (nonlinear case) forms
            specifying the primal problem and the goal

        object_names (dict)
            Map from object ids to object names

        reserved_names (dict)
            Map from reserved object names to object ids

    *Returns*

        tuple (of length 3) containing

        Form or tuple
            A single linear form or a tuple of a bilinear and a linear
            form

        Form
            A linear form or a functional for the goal functional

        Coefficient
            The coefficient considered as the unknown
    """

    # Check that we get a tuple of forms
    expecting_tuple_msg = "Expecting tuple of forms, got %s" % str(forms)
    assert(isinstance(forms, (list, tuple))), expecting_tuple_msg

    def __is_nonlinear(forms):
        return len(forms) == 2

    def __is_linear(forms):
        return len(forms) == 3

    # Extract Coefficient labelled as 'unknown'
    u = reserved_objects.get("unknown", None)

    if __is_nonlinear(forms):
        (F, M) = forms

        # Check that unknown is defined
        assert (u), "Can't extract 'unknown'. The Coefficient representing the unknown must be labelled by 'unknown' for nonlinear problems."

        # Check that forms have the expected rank
        assert(len(extract_arguments(F)) == 1)
        assert(len(extract_arguments(M)) == 0)

        # Return primal, goal and unknown
        return (F, M, u)

    elif __is_linear(forms):
        # Throw error if unknown is given, don't quite know what to do
        # with this case yet
        if u:
            error("'unknown' defined: not implemented for linear problems")

        (a, L, M) = forms

        # Check that forms have the expected rank
        arguments = extract_arguments(a)
        assert(len(arguments) == 2)
        assert(len(extract_arguments(L)) == 1)
        assert(len(extract_arguments(M)) == 1)

        # Standard case: create default Coefficient in trial space and
        # label it __discrete_primal_solution
        V = arguments[1].element()
        u = Coefficient(V)
        object_names[id(u)] = "__discrete_primal_solution"

        return ((a, L), M, u)

    else:
        error("Wrong input tuple length: got %s, expected 2 or 3-tuple"
              % str(forms))
Beispiel #22
0
def compile_element(expression, dual_space=None, parameters=None,
                    name="evaluate"):
    """Generate code for point evaluations.

    :arg expression: A UFL expression (may contain up to one coefficient, or one argument)
    :arg dual_space: if the expression has an argument, should we also distribute residual data?
    :returns: Some coffee AST
    """
    if parameters is None:
        parameters = default_parameters()
    else:
        _ = default_parameters()
        _.update(parameters)
        parameters = _

    expression = tsfc.ufl_utils.preprocess_expression(expression)

    # # Collect required coefficients

    try:
        arg, = extract_coefficients(expression)
        argument_multiindices = ()
        coefficient = True
        if expression.ufl_shape:
            tensor_indices = tuple(gem.Index() for s in expression.ufl_shape)
        else:
            tensor_indices = ()
    except ValueError:
        arg, = extract_arguments(expression)
        finat_elem = create_element(arg.ufl_element())
        argument_multiindices = (finat_elem.get_indices(), )
        argument_multiindex, = argument_multiindices
        value_shape = finat_elem.value_shape
        if value_shape:
            tensor_indices = argument_multiindex[-len(value_shape):]
        else:
            tensor_indices = ()
        coefficient = False

    # Replace coordinates (if any)
    builder = firedrake_interface.KernelBuilderBase()
    domain = expression.ufl_domain()
    # Translate to GEM
    cell = domain.ufl_cell()
    dim = cell.topological_dimension()
    point = gem.Variable('X', (dim,))
    point_arg = ast.Decl(SCALAR_TYPE, ast.Symbol('X', rank=(dim,)))

    config = dict(interface=builder,
                  ufl_cell=cell,
                  precision=parameters["precision"],
                  point_indices=(),
                  point_expr=point,
                  argument_multiindices=argument_multiindices)
    context = tsfc.fem.GemPointContext(**config)

    # Abs-simplification
    expression = tsfc.ufl_utils.simplify_abs(expression)

    # Translate UFL -> GEM
    if coefficient:
        assert dual_space is None
        f_arg = [builder._coefficient(arg, "f")]
    else:
        f_arg = []
    translator = tsfc.fem.Translator(context)
    result, = map_expr_dags(translator, [expression])

    b_arg = []
    if coefficient:
        if expression.ufl_shape:
            return_variable = gem.Indexed(gem.Variable('R', expression.ufl_shape), tensor_indices)
            result_arg = ast.Decl(SCALAR_TYPE, ast.Symbol('R', rank=expression.ufl_shape))
            result = gem.Indexed(result, tensor_indices)
        else:
            return_variable = gem.Indexed(gem.Variable('R', (1,)), (0,))
            result_arg = ast.Decl(SCALAR_TYPE, ast.Symbol('R', rank=(1,)))

    else:
        return_variable = gem.Indexed(gem.Variable('R', finat_elem.index_shape), argument_multiindex)
        result = gem.Indexed(result, tensor_indices)
        if dual_space:
            elem = create_element(dual_space.ufl_element())
            if elem.value_shape:
                var = gem.Indexed(gem.Variable("b", elem.value_shape),
                                  tensor_indices)
                b_arg = [ast.Decl(SCALAR_TYPE, ast.Symbol("b", rank=elem.value_shape))]
            else:
                var = gem.Indexed(gem.Variable("b", (1, )), (0, ))
                b_arg = [ast.Decl(SCALAR_TYPE, ast.Symbol("b", rank=(1, )))]
            result = gem.Product(result, var)

        result_arg = ast.Decl(SCALAR_TYPE, ast.Symbol('R', rank=finat_elem.index_shape))

    # Unroll
    max_extent = parameters["unroll_indexsum"]
    if max_extent:
        def predicate(index):
            return index.extent <= max_extent
        result, = gem.optimise.unroll_indexsum([result], predicate=predicate)

    # Translate GEM -> COFFEE
    result, = gem.impero_utils.preprocess_gem([result])
    impero_c = gem.impero_utils.compile_gem([(return_variable, result)], tensor_indices)
    body = generate_coffee(impero_c, {}, parameters["precision"])

    # Build kernel tuple
    kernel_code = builder.construct_kernel("pyop2_kernel_" + name, [result_arg] + b_arg + f_arg + [point_arg], body)

    return kernel_code
Beispiel #23
0
def compile_element(expression,
                    dual_space=None,
                    parameters=None,
                    name="evaluate"):
    """Generate code for point evaluations.

    :arg expression: A UFL expression (may contain up to one coefficient, or one argument)
    :arg dual_space: if the expression has an argument, should we also distribute residual data?
    :returns: Some coffee AST
    """
    if parameters is None:
        parameters = default_parameters()
    else:
        _ = default_parameters()
        _.update(parameters)
        parameters = _

    expression = tsfc.ufl_utils.preprocess_expression(expression)

    # # Collect required coefficients

    try:
        arg, = extract_coefficients(expression)
        argument_multiindices = ()
        coefficient = True
        if expression.ufl_shape:
            tensor_indices = tuple(gem.Index() for s in expression.ufl_shape)
        else:
            tensor_indices = ()
    except ValueError:
        arg, = extract_arguments(expression)
        finat_elem = create_element(arg.ufl_element())
        argument_multiindices = (finat_elem.get_indices(), )
        argument_multiindex, = argument_multiindices
        value_shape = finat_elem.value_shape
        if value_shape:
            tensor_indices = argument_multiindex[-len(value_shape):]
        else:
            tensor_indices = ()
        coefficient = False

    # Replace coordinates (if any)
    builder = firedrake_interface.KernelBuilderBase(scalar_type=ScalarType_c)
    domain = expression.ufl_domain()
    # Translate to GEM
    cell = domain.ufl_cell()
    dim = cell.topological_dimension()
    point = gem.Variable('X', (dim, ))
    point_arg = ast.Decl(ScalarType_c, ast.Symbol('X', rank=(dim, )))

    config = dict(interface=builder,
                  ufl_cell=cell,
                  precision=parameters["precision"],
                  point_indices=(),
                  point_expr=point,
                  argument_multiindices=argument_multiindices)
    context = tsfc.fem.GemPointContext(**config)

    # Abs-simplification
    expression = tsfc.ufl_utils.simplify_abs(expression)

    # Translate UFL -> GEM
    if coefficient:
        assert dual_space is None
        f_arg = [builder._coefficient(arg, "f")]
    else:
        f_arg = []
    translator = tsfc.fem.Translator(context)
    result, = map_expr_dags(translator, [expression])

    b_arg = []
    if coefficient:
        if expression.ufl_shape:
            return_variable = gem.Indexed(
                gem.Variable('R', expression.ufl_shape), tensor_indices)
            result_arg = ast.Decl(ScalarType_c,
                                  ast.Symbol('R', rank=expression.ufl_shape))
            result = gem.Indexed(result, tensor_indices)
        else:
            return_variable = gem.Indexed(gem.Variable('R', (1, )), (0, ))
            result_arg = ast.Decl(ScalarType_c, ast.Symbol('R', rank=(1, )))

    else:
        return_variable = gem.Indexed(
            gem.Variable('R', finat_elem.index_shape), argument_multiindex)
        result = gem.Indexed(result, tensor_indices)
        if dual_space:
            elem = create_element(dual_space.ufl_element())
            if elem.value_shape:
                var = gem.Indexed(gem.Variable("b", elem.value_shape),
                                  tensor_indices)
                b_arg = [
                    ast.Decl(ScalarType_c,
                             ast.Symbol("b", rank=elem.value_shape))
                ]
            else:
                var = gem.Indexed(gem.Variable("b", (1, )), (0, ))
                b_arg = [ast.Decl(ScalarType_c, ast.Symbol("b", rank=(1, )))]
            result = gem.Product(result, var)

        result_arg = ast.Decl(ScalarType_c,
                              ast.Symbol('R', rank=finat_elem.index_shape))

    # Unroll
    max_extent = parameters["unroll_indexsum"]
    if max_extent:

        def predicate(index):
            return index.extent <= max_extent

        result, = gem.optimise.unroll_indexsum([result], predicate=predicate)

    # Translate GEM -> COFFEE
    result, = gem.impero_utils.preprocess_gem([result])
    impero_c = gem.impero_utils.compile_gem([(return_variable, result)],
                                            tensor_indices)
    body = generate_coffee(impero_c, {}, parameters["precision"], ScalarType_c)

    # Build kernel tuple
    kernel_code = builder.construct_kernel(
        "pyop2_kernel_" + name, [result_arg] + b_arg + f_arg + [point_arg],
        body)

    return kernel_code
Beispiel #24
0
def splitMultiLinearExpr(expr, arguments=None):
    if arguments is None:
        arguments = extract_arguments(expr)
    return MultiLinearExprSplitter(arguments).visit(expr)