Esempio n. 1
0
    def __init__(self, integral_type, subdomain_id, domain_number):
        """Initialise a kernel builder."""
        super(KernelBuilder,
              self).__init__(integral_type.startswith("interior_facet"))

        self.kernel = Kernel(integral_type=integral_type,
                             subdomain_id=subdomain_id,
                             domain_number=domain_number)
        self.local_tensor = None
        self.coordinates_arg = None
        self.coefficient_args = []
        self.coefficient_split = {}

        # Facet number
        if integral_type in ['exterior_facet', 'exterior_facet_vert']:
            facet = gem.Variable('facet', (1, ))
            self._facet_number = {
                None: gem.VariableIndex(gem.Indexed(facet, (0, )))
            }
        elif integral_type in ['interior_facet', 'interior_facet_vert']:
            facet = gem.Variable('facet', (2, ))
            self._facet_number = {
                '+': gem.VariableIndex(gem.Indexed(facet, (0, ))),
                '-': gem.VariableIndex(gem.Indexed(facet, (1, )))
            }
        elif integral_type == 'interior_facet_horiz':
            self._facet_number = {'+': 1, '-': 0}
Esempio n. 2
0
def translate_coefficient(terminal, mt, ctx):
    vec = ctx.coefficient(terminal, mt.restriction)

    if terminal.ufl_element().family() == 'Real':
        assert mt.local_derivatives == 0
        return vec

    element = ctx.create_element(terminal.ufl_element())

    # Collect FInAT tabulation for all entities
    per_derivative = collections.defaultdict(list)
    for entity_id in ctx.entity_ids:
        finat_dict = ctx.basis_evaluation(element, mt.local_derivatives, entity_id)
        for alpha, table in finat_dict.items():
            # Filter out irrelevant derivatives
            if sum(alpha) == mt.local_derivatives:
                # A numerical hack that FFC used to apply on FIAT
                # tables still lives on after ditching FFC and
                # switching to FInAT.
                table = ffc_rounding(table, ctx.epsilon)
                per_derivative[alpha].append(table)

    # Merge entity tabulations for each derivative
    if len(ctx.entity_ids) == 1:
        def take_singleton(xs):
            x, = xs  # asserts singleton
            return x
        per_derivative = {alpha: take_singleton(tables)
                          for alpha, tables in per_derivative.items()}
    else:
        f = ctx.entity_number(mt.restriction)
        per_derivative = {alpha: gem.select_expression(tables, f)
                          for alpha, tables in per_derivative.items()}

    # Coefficient evaluation
    ctx.index_cache.setdefault(terminal.ufl_element(), element.get_indices())
    beta = ctx.index_cache[terminal.ufl_element()]
    zeta = element.get_value_indices()
    vec_beta, = gem.optimise.remove_componenttensors([gem.Indexed(vec, beta)])
    value_dict = {}
    for alpha, table in per_derivative.items():
        table_qi = gem.Indexed(table, beta + zeta)
        summands = []
        for var, expr in unconcatenate([(vec_beta, table_qi)], ctx.index_cache):
            value = gem.IndexSum(gem.Product(expr, var), var.index_ordering())
            summands.append(gem.optimise.contraction(value))
        optimised_value = gem.optimise.make_sum(summands)
        value_dict[alpha] = gem.ComponentTensor(optimised_value, zeta)

    # Change from FIAT to UFL arrangement
    result = fiat_to_ufl(value_dict, mt.local_derivatives)
    assert result.shape == mt.expr.ufl_shape
    assert set(result.free_indices) <= set(ctx.point_indices)

    # Detect Jacobian of affine cells
    if not result.free_indices and all(numpy.count_nonzero(node.array) <= 2
                                       for node in traversal((result,))
                                       if isinstance(node, gem.Literal)):
        result = gem.optimise.aggressive_unroll(result)
    return result
Esempio n. 3
0
def test_expressions():
    x = gem.Variable("x", (3, 4))
    y = gem.Variable("y", (4, ))
    i, j = gem.indices(2)

    xij = x[i, j]
    yj = y[j]

    assert xij == gem.Indexed(x, (i, j))
    assert yj == gem.Indexed(y, (j, ))

    assert xij + yj == gem.Sum(xij, yj)
    assert xij * yj == gem.Product(xij, yj)
    assert xij - yj == gem.Sum(xij, gem.Product(gem.Literal(-1), yj))
    assert xij / yj == gem.Division(xij, yj)

    assert xij + 1 == gem.Sum(xij, gem.Literal(1))
    assert 1 + xij == gem.Sum(gem.Literal(1), xij)

    assert (xij + y).shape == (4, )

    assert (x @ y).shape == (3, )

    assert x.T.shape == (4, 3)

    with pytest.raises(ValueError):
        xij.T @ y

    with pytest.raises(ValueError):
        xij + "foo"
Esempio n. 4
0
    def _entity_support_dofs(self):
        esd = {}
        for entity_dim in self.cell.sub_entities.keys():
            beta = self.get_indices()
            zeta = self.get_value_indices()

            entity_cell = self.cell.construct_subelement(entity_dim)
            quad = make_quadrature(entity_cell,
                                   (2 * numpy.array(self.degree)).tolist())

            eps = 1.e-8  # Is this a safe value?

            result = {}
            for f in self.entity_dofs()[entity_dim].keys():
                # Tabulate basis functions on the facet
                vals, = self.basis_evaluation(0,
                                              quad.point_set,
                                              entity=(entity_dim, f)).values()
                # Integrate the square of the basis functions on the facet.
                ints = gem.IndexSum(
                    gem.Product(
                        gem.IndexSum(
                            gem.Product(gem.Indexed(vals, beta + zeta),
                                        gem.Indexed(vals, beta + zeta)), zeta),
                        quad.weight_expression), quad.point_set.indices)
                evaluation, = evaluate([gem.ComponentTensor(ints, beta)])
                ints = evaluation.arr.flatten()
                assert evaluation.fids == ()
                result[f] = [dof for dof, i in enumerate(ints) if i > eps]

            esd[entity_dim] = result
        return esd
 def conditional(self, o, condition, then, else_):
     assert condition.shape == ()
     shape, = set([then.shape, else_.shape])
     indices = gem.indices(len(shape))
     return gem.ComponentTensor(
         gem.Conditional(condition, gem.Indexed(then, indices),
                         gem.Indexed(else_, indices)), indices)
Esempio n. 6
0
def gem_to_loopy(gem_expr, var2terminal, scalar_type):
    """ Method encapsulating stage 2.
    Converts the gem expression dag into imperoc first, and then further into loopy.
    :return slate_loopy: 2-tuple of loopy kernel for slate operations
        and loopy GlobalArg for the output variable.
    """
    # Creation of return variables for outer loopy
    shape = gem_expr.shape if len(gem_expr.shape) != 0 else (1, )
    idx = make_indices(len(shape))
    indexed_gem_expr = gem.Indexed(gem_expr, idx)
    args = ([
        loopy.GlobalArg("output",
                        shape=shape,
                        dtype=scalar_type,
                        is_output=True,
                        is_input=True)
    ] + [
        loopy.GlobalArg(var.name, shape=var.shape, dtype=scalar_type)
        for var in var2terminal.keys()
    ])
    ret_vars = [gem.Indexed(gem.Variable("output", shape), idx)]

    preprocessed_gem_expr = impero_utils.preprocess_gem([indexed_gem_expr])

    # glue assignments to return variable
    assignments = list(zip(ret_vars, preprocessed_gem_expr))

    # Part A: slate to impero_c
    impero_c = impero_utils.compile_gem(assignments, (), remove_zeros=False)

    # Part B: impero_c to loopy
    return generate_loopy(impero_c, args, scalar_type, "slate_loopy",
                          []), args[0].copy()
Esempio n. 7
0
def point_evaluation_ciarlet(fiat_element, order, refcoords, entity):
    # Coordinates on the reference entity (SymPy)
    esd, = refcoords.shape
    Xi = sp.symbols('X Y Z')[:esd]

    # Coordinates on the reference cell
    cell = fiat_element.get_reference_element()
    X = cell.get_entity_transform(*entity)(Xi)

    # Evaluate expansion set at SymPy point
    poly_set = fiat_element.get_nodal_basis()
    degree = poly_set.get_embedded_degree()
    base_values = poly_set.get_expansion_set().tabulate(degree, [X])
    m = len(base_values)
    assert base_values.shape == (m, 1)
    base_values_sympy = np.array(list(base_values.flat))

    # Find constant polynomials
    def is_const(expr):
        try:
            float(expr)
            return True
        except TypeError:
            return False

    const_mask = np.array(list(map(is_const, base_values_sympy)))

    # Convert SymPy expression to GEM
    mapper = gem.node.Memoizer(sympy2gem)
    mapper.bindings = {
        s: gem.Indexed(refcoords, (i, ))
        for i, s in enumerate(Xi)
    }
    base_values = gem.ListTensor(list(map(mapper, base_values.flat)))

    # Populate result dict, creating precomputed coefficient
    # matrices for each derivative tuple.
    result = {}
    for i in range(order + 1):
        for alpha in mis(cell.get_spatial_dimension(), i):
            D = form_matrix_product(poly_set.get_dmats(), alpha)
            table = np.dot(poly_set.get_coeffs(), np.transpose(D))
            assert table.shape[-1] == m
            zerocols = np.isclose(
                abs(table).max(axis=tuple(range(table.ndim - 1))), 0.0)
            if all(np.logical_or(const_mask, zerocols)):
                # Casting is safe by assertion of is_const
                vals = base_values_sympy[const_mask].astype(np.float64)
                result[alpha] = gem.Literal(table[..., const_mask].dot(vals))
            else:
                beta = tuple(gem.Index() for s in table.shape[:-1])
                k = gem.Index()
                result[alpha] = gem.ComponentTensor(
                    gem.IndexSum(
                        gem.Product(
                            gem.Indexed(gem.Literal(table), beta + (k, )),
                            gem.Indexed(base_values, (k, ))), (k, )), beta)
    return result
Esempio n. 8
0
def compile_to_gem(expr, translator):
    """Compile a single pointwise expression to GEM.

    :arg expr: The expression to compile.
    :arg translator: a :class:`Translator` instance.
    :returns: A (lvalue, rvalue) pair of preprocessed GEM."""
    if not isinstance(expr, Assign):
        raise ValueError(
            f"Don't know how to assign expression of type {type(expr)}")
    spaces = tuple(c.function_space() for c in expr.coefficients)
    if any(
            type(s.ufl_element()) is ufl.MixedElement for s in spaces
            if s is not None):
        raise ValueError("Not expecting a mixed space at this point, "
                         "did you forget to index a function with .sub(...)?")
    if len(set(s.ufl_element() for s in spaces if s is not None)) != 1:
        raise ValueError("All coefficients must be defined on the same space")
    lvalue = expr.lvalue
    rvalue = expr.rvalue
    broadcast = all(
        isinstance(c, firedrake.Constant)
        for c in expr.rcoefficients) and rvalue.ufl_shape == ()
    if not broadcast and lvalue.ufl_shape != rvalue.ufl_shape:
        try:
            rvalue = reshape(rvalue, lvalue.ufl_shape)
        except ValueError:
            raise ValueError(
                "Mismatching shapes between lvalue and rvalue in pointwise assignment"
            )
    rvalue, = map_expr_dags(LowerCompoundAlgebra(), [rvalue])
    try:
        lvalue, rvalue = map_expr_dags(translator, [lvalue, rvalue])
    except (AssertionError, ValueError):
        raise ValueError("Mismatching shapes in pointwise assignment. "
                         "For intrinsically vector-/tensor-valued spaces make "
                         "sure you're not using shaped Constants or literals.")

    indices = gem.indices(len(lvalue.shape))
    if not broadcast:
        if rvalue.shape != lvalue.shape:
            raise ValueError(
                "Mismatching shapes in pointwise assignment. "
                "For intrinsically vector-/tensor-valued spaces make "
                "sure you're not using shaped Constants or literals.")
        rvalue = gem.Indexed(rvalue, indices)
    lvalue = gem.Indexed(lvalue, indices)
    if isinstance(expr, IAdd):
        rvalue = gem.Sum(lvalue, rvalue)
    elif isinstance(expr, ISub):
        rvalue = gem.Sum(lvalue, gem.Product(gem.Literal(-1), rvalue))
    elif isinstance(expr, IMul):
        rvalue = gem.Product(lvalue, rvalue)
    elif isinstance(expr, IDiv):
        rvalue = gem.Division(lvalue, rvalue)
    return preprocess_gem([lvalue, rvalue])
Esempio n. 9
0
    def basis_evaluation(self, order, ps, entity=None):
        '''Return code for evaluating the element at known points on the
        reference element.

        :param order: return derivatives up to this order.
        :param ps: the point set.
        :param entity: the cell entity on which to tabulate.
        '''
        space_dimension = self._element.space_dimension()
        value_size = np.prod(self._element.value_shape(), dtype=int)
        fiat_result = self._element.tabulate(order, ps.points, entity)
        result = {}
        for alpha, fiat_table in iteritems(fiat_result):
            if isinstance(fiat_table, Exception):
                result[alpha] = gem.Failure(
                    self.index_shape + self.value_shape, fiat_table)
                continue

            derivative = sum(alpha)
            table_roll = fiat_table.reshape(space_dimension, value_size,
                                            len(ps.points)).transpose(1, 2, 0)

            exprs = []
            for table in table_roll:
                if derivative < self.degree:
                    point_indices = ps.indices
                    point_shape = tuple(index.extent
                                        for index in point_indices)
                    exprs.append(
                        gem.partial_indexed(
                            gem.Literal(
                                table.reshape(point_shape + self.index_shape)),
                            point_indices))
                elif derivative == self.degree:
                    # Make sure numerics satisfies theory
                    assert np.allclose(table, table.mean(axis=0,
                                                         keepdims=True))
                    exprs.append(gem.Literal(table[0]))
                else:
                    # Make sure numerics satisfies theory
                    assert np.allclose(table, 0.0)
                    exprs.append(gem.Zero(self.index_shape))
            if self.value_shape:
                beta = self.get_indices()
                zeta = self.get_value_indices()
                result[alpha] = gem.ComponentTensor(
                    gem.Indexed(
                        gem.ListTensor(
                            np.array([
                                gem.Indexed(expr, beta) for expr in exprs
                            ]).reshape(self.value_shape)), zeta), beta + zeta)
            else:
                expr, = exprs
                result[alpha] = expr
        return result
    def to_reference_coordinates(ufl_coordinate_element):
        # Set up UFL form
        cell = ufl_coordinate_element.cell()
        domain = ufl.Mesh(ufl_coordinate_element)
        K = ufl.JacobianInverse(domain)
        x = ufl.SpatialCoordinate(domain)
        x0_element = ufl.VectorElement("Real", cell, 0)
        x0 = ufl.Coefficient(ufl.FunctionSpace(domain, x0_element))
        expr = ufl.dot(K, x - x0)

        # Translation to GEM
        C = ufl_utils.coordinate_coefficient(domain)
        expr = ufl_utils.preprocess_expression(expr)
        expr = ufl_utils.replace_coordinates(expr, C)
        expr = ufl_utils.simplify_abs(expr)

        builder = firedrake_interface.KernelBuilderBase()
        builder._coefficient(C, "C")
        builder._coefficient(x0, "x0")

        dim = cell.topological_dimension()
        point = gem.Variable('X', (dim, ))
        context = tsfc.fem.GemPointContext(
            interface=builder,
            ufl_cell=cell,
            precision=parameters["precision"],
            point_indices=(),
            point_expr=point,
        )
        translator = tsfc.fem.Translator(context)
        ir = map_expr_dag(translator, expr)

        # Unroll result
        ir = [gem.Indexed(ir, alpha) for alpha in numpy.ndindex(ir.shape)]

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

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

        ir = gem.optimise.unroll_indexsum(ir, predicate=predicate)

        # Translate to COFFEE
        ir = impero_utils.preprocess_gem(ir)
        return_variable = gem.Variable('dX', (dim, ))
        assignments = [(gem.Indexed(return_variable, (i, )), e)
                       for i, e in enumerate(ir)]
        impero_c = impero_utils.compile_gem(assignments, ())
        body = tsfc.coffee.generate(impero_c, {}, parameters["precision"])
        body.open_scope = False

        return body
Esempio n. 11
0
def test_pickle_gem(protocol):
    f = gem.VariableIndex(gem.Indexed(gem.Variable('facet', (2, )), (1, )))
    q = gem.Index()
    r = gem.Index()
    _1 = gem.Indexed(gem.Literal(numpy.random.rand(3, 6, 8)), (f, q, r))
    _2 = gem.Indexed(
        gem.view(gem.Variable('w', (None, None)), slice(8), slice(1)), (r, 0))
    expr = gem.ComponentTensor(gem.IndexSum(gem.Product(_1, _2), (r, )), (q, ))

    unpickled = pickle.loads(pickle.dumps(expr, protocol))
    assert repr(expr) == repr(unpickled)
Esempio n. 12
0
 def merge(tables):
     tables = tuple(tables)
     zeta = self.get_value_indices()
     tensors = []
     for elem, table in zip(self.elements, tables):
         beta_i = elem.get_indices()
         tensors.append(
             gem.ComponentTensor(gem.Indexed(table, beta_i + zeta),
                                 beta_i))
     beta = self.get_indices()
     return gem.ComponentTensor(
         gem.Indexed(gem.Concatenate(*tensors), beta), beta + zeta)
Esempio n. 13
0
def test_refactorise():
    f = gem.Variable('f', (3,))
    u = gem.Variable('u', (3,))
    v = gem.Variable('v', ())

    i = gem.Index()
    f_i = gem.Indexed(f, (i,))
    u_i = gem.Indexed(u, (i,))

    def classify(atomics_set, expression):
        if expression in atomics_set:
            return ATOMIC

        for node in traversal([expression]):
            if node in atomics_set:
                return COMPOUND

        return OTHER
    classifier = partial(classify, {u_i, v})

    # \sum_i 5*(2*u_i + -1*v)*(u_i + v*f)
    expr = gem.IndexSum(
        gem.Product(
            gem.Literal(5),
            gem.Product(
                gem.Sum(gem.Product(gem.Literal(2), u_i),
                        gem.Product(gem.Literal(-1), v)),
                gem.Sum(u_i, gem.Product(v, f_i))
            )
        ),
        (i,)
    )

    expected = [
        Monomial((i,),
                 (u_i, u_i),
                 gem.Literal(10)),
        Monomial((i,),
                 (u_i, v),
                 gem.Product(gem.Literal(5),
                             gem.Sum(gem.Product(f_i, gem.Literal(2)),
                                     gem.Literal(-1)))),
        Monomial((),
                 (v, v),
                 gem.Product(gem.Literal(5),
                             gem.IndexSum(gem.Product(f_i, gem.Literal(-1)),
                                          (i,)))),
    ]

    actual, = collect_monomials([expr], classifier)
    assert expected == list(actual)
Esempio n. 14
0
    def __init__(self, interior_facet=False):
        """Initialise a kernel builder.

        :arg interior_facet: kernel accesses two cells
        """
        super(KernelBuilderBase, self).__init__(interior_facet=interior_facet)

        # Cell orientation
        if self.interior_facet:
            cell_orientations = gem.Variable("cell_orientations", (2, ))
            self._cell_orientations = (gem.Indexed(cell_orientations, (0, )),
                                       gem.Indexed(cell_orientations, (1, )))
        else:
            cell_orientations = gem.Variable("cell_orientations", (1, ))
            self._cell_orientations = (gem.Indexed(cell_orientations, (0, )), )
Esempio n. 15
0
File: fem.py Progetto: knut0815/tsfc
def translate_cell_edge_vectors(terminal, mt, ctx):
    # WARNING: Assumes straight edges!
    coords = CellVertices(terminal.ufl_domain())
    ufl_expr = construct_modified_terminal(mt, coords)
    cell_vertices = ctx.translator(ufl_expr)

    e = gem.Index()
    c = gem.Index()
    expr = gem.ListTensor([
        gem.Sum(
            gem.Indexed(cell_vertices, (u, c)),
            gem.Product(gem.Literal(-1), gem.Indexed(cell_vertices, (v, c))))
        for _, (u, v) in sorted(ctx.fiat_cell.get_topology()[1].items())
    ])
    return gem.ComponentTensor(gem.Indexed(expr, (e, )), (e, c))
Esempio n. 16
0
    def point_evaluation(self, order, point, entity=None):
        entities = self._factor_entity(entity)
        entity_dim, _ = zip(*entities)

        # Split point expression
        assert len(self.cell.cells) == len(entity_dim)
        point_dims = [
            cell.construct_subelement(dim).get_spatial_dimension()
            for cell, dim in zip(self.cell.cells, entity_dim)
        ]
        assert isinstance(point,
                          gem.Node) and point.shape == (sum(point_dims), )
        slices = TensorProductCell._split_slices(point_dims)
        point_factors = []
        for s in slices:
            point_factors.append(
                gem.ListTensor([
                    gem.Indexed(point, (i, )) for i in range(s.start, s.stop)
                ]))

        # Subelement results
        factor_results = [
            fe.point_evaluation(order, p_, e)
            for fe, p_, e in zip(self.factors, point_factors, entities)
        ]

        return self._merge_evaluations(factor_results)
Esempio n. 17
0
    def basis_evaluation(self, order, ps, entity=None):
        r"""Produce the recipe for basis function evaluation at a set of points :math:`q`:

        .. math::
            \boldsymbol\phi_{(\gamma \epsilon) (i \alpha \beta) q} = \delta_{\alpha \gamma}\delta{\beta \epsilon}\phi_{i q}

            \nabla\boldsymbol\phi_{(\epsilon \gamma \zeta) (i \alpha \beta) q} = \delta_{\alpha \epsilon} \deta{\beta \gamma}\nabla\phi_{\zeta i q}
        """
        # Old basis function and value indices
        scalar_i = self._base_element.get_indices()
        scalar_vi = self._base_element.get_value_indices()

        # New basis function and value indices
        tensor_i = tuple(gem.Index(extent=d) for d in self._shape)
        tensor_vi = tuple(gem.Index(extent=d) for d in self._shape)

        # Couple new basis function and value indices
        deltas = reduce(gem.Product,
                        (gem.Delta(j, k) for j, k in zip(tensor_i, tensor_vi)))

        scalar_result = self._base_element.basis_evaluation(order, ps, entity)
        result = {}
        for alpha, expr in iteritems(scalar_result):
            result[alpha] = gem.ComponentTensor(
                gem.Product(deltas, gem.Indexed(expr, scalar_i + scalar_vi)),
                scalar_i + tensor_i + scalar_vi + tensor_vi)
        return result
Esempio n. 18
0
    def _tensorise(self, scalar_evaluation):
        # Old basis function and value indices
        scalar_i = self._base_element.get_indices()
        scalar_vi = self._base_element.get_value_indices()

        # New basis function and value indices
        tensor_i = tuple(gem.Index(extent=d) for d in self._shape)
        tensor_vi = tuple(gem.Index(extent=d) for d in self._shape)

        # Couple new basis function and value indices
        deltas = reduce(gem.Product, (gem.Delta(j, k)
                                      for j, k in zip(tensor_i, tensor_vi)))

        if self._transpose:
            index_ordering = tensor_i + scalar_i + tensor_vi + scalar_vi
        else:
            index_ordering = scalar_i + tensor_i + tensor_vi + scalar_vi

        result = {}
        for alpha, expr in scalar_evaluation.items():
            result[alpha] = gem.ComponentTensor(
                gem.Product(deltas, gem.Indexed(expr, scalar_i + scalar_vi)),
                index_ordering
            )
        return result
Esempio n. 19
0
File: fem.py Progetto: jmv2009/tsfc
 def physical_points(self, point_set, entity=None):
     """Converts point_set from reference to physical space"""
     expr = SpatialCoordinate(self.mt.terminal.ufl_domain())
     point_shape, = point_set.expression.shape
     if entity is not None:
         e, _ = entity
         assert point_shape == e
     else:
         assert point_shape == expr.ufl_domain().topological_dimension()
     if self.mt.restriction == '+':
         expr = PositiveRestricted(expr)
     elif self.mt.restriction == '-':
         expr = NegativeRestricted(expr)
     config = {"point_set": point_set}
     config.update(self.config)
     if entity is not None:
         config.update({
             name: getattr(self.interface, name)
             for name in ["integration_dim", "entity_ids"]
         })
     context = PointSetContext(**config)
     expr = self.preprocess(expr, context)
     mapped = map_expr_dag(context.translator, expr)
     indices = tuple(gem.Index() for _ in mapped.shape)
     return gem.ComponentTensor(gem.Indexed(mapped, indices),
                                point_set.indices + indices)
Esempio n. 20
0
def einsum(factors, sum_indices):
    """Evaluates a tensor product at compile time.

    :arg factors: iterable of indexed GEM literals
    :arg sum_indices: indices to sum over
    :returns: a single indexed GEM literal
    """
    # Maps the problem onto numpy.einsum
    index2letter = defaultdict(partial(lambda c: chr(ord('i') + next(c)), count()))
    operands = []
    subscript_parts = []
    for factor in factors:
        literal, = factor.children
        selectors = []
        letters = []
        for index in factor.multiindex:
            if isinstance(index, int):
                selectors.append(index)
            else:
                selectors.append(slice(None))
                letters.append(index2letter[index])
        operands.append(literal.array.__getitem__(tuple(selectors)))
        subscript_parts.append(''.join(letters))

    result_pairs = sorted((letter, index)
                          for index, letter in index2letter.items()
                          if index not in sum_indices)

    subscripts = ','.join(subscript_parts) + '->' + ''.join(l for l, i in result_pairs)
    tensor = numpy.einsum(subscripts, *operands)
    return gem.Indexed(gem.Literal(tensor), tuple(i for l, i in result_pairs))
Esempio n. 21
0
File: fem.py Progetto: knut0815/tsfc
def translate_argument(terminal, mt, ctx):
    argument_multiindex = ctx.argument_multiindices[terminal.number()]
    sigma = tuple(gem.Index(extent=d) for d in mt.expr.ufl_shape)
    element = ctx.create_element(terminal.ufl_element(),
                                 restriction=mt.restriction)

    def callback(entity_id):
        finat_dict = ctx.basis_evaluation(element, mt, entity_id)
        # Filter out irrelevant derivatives
        filtered_dict = {
            alpha: table
            for alpha, table in finat_dict.items()
            if sum(alpha) == mt.local_derivatives
        }

        # Change from FIAT to UFL arrangement
        square = fiat_to_ufl(filtered_dict, mt.local_derivatives)

        # A numerical hack that FFC used to apply on FIAT tables still
        # lives on after ditching FFC and switching to FInAT.
        return ffc_rounding(square, ctx.epsilon)

    table = ctx.entity_selector(callback, mt.restriction)
    return gem.ComponentTensor(gem.Indexed(table, argument_multiindex + sigma),
                               sigma)
Esempio n. 22
0
 def matvec(table):
     i, j = gem.indices(2)
     value_indices = self.get_value_indices()
     table = gem.Indexed(table, (j, ) + value_indices)
     val = gem.ComponentTensor(gem.IndexSum(M[i, j] * table, (j, )),
                               (i, ) + value_indices)
     # Eliminate zeros
     return gem.optimise.aggressive_unroll(val)
Esempio n. 23
0
def prepare_arguments(arguments, multiindices, scalar_type, interior_facet=False, diagonal=False):
    """Bridges the kernel interface and the GEM abstraction for
    Arguments.  Vector Arguments are rearranged here for interior
    facet integrals.

    :arg arguments: UFL Arguments
    :arg multiindices: Argument multiindices
    :arg interior_facet: interior facet integral?
    :arg diagonal: Are we assembling the diagonal of a rank-2 element tensor?
    :returns: (funarg, expression)
         funarg      - :class:`loopy.GlobalArg` function argument
         expressions - GEM expressions referring to the argument
                       tensor
    """

    assert isinstance(interior_facet, bool)

    if len(arguments) == 0:
        # No arguments
        funarg = lp.GlobalArg("A", dtype=scalar_type, shape=(1,))
        expression = gem.Indexed(gem.Variable("A", (1,)), (0,))

        return funarg, [expression]

    elements = tuple(create_element(arg.ufl_element()) for arg in arguments)
    shapes = tuple(element.index_shape for element in elements)

    if diagonal:
        if len(arguments) != 2:
            raise ValueError("Diagonal only for 2-forms")
        try:
            element, = set(elements)
        except ValueError:
            raise ValueError("Diagonal only for diagonal blocks (test and trial spaces the same)")

        elements = (element, )
        shapes = tuple(element.index_shape for element in elements)
        multiindices = multiindices[:1]

    def expression(restricted):
        return gem.Indexed(gem.reshape(restricted, *shapes),
                           tuple(chain(*multiindices)))

    u_shape = numpy.array([numpy.prod(shape, dtype=int) for shape in shapes])
    if interior_facet:
        c_shape = tuple(2 * u_shape)
        slicez = [[slice(r * s, (r + 1) * s)
                   for r, s in zip(restrictions, u_shape)]
                  for restrictions in product((0, 1), repeat=len(arguments))]
    else:
        c_shape = tuple(u_shape)
        slicez = [[slice(s) for s in u_shape]]

    funarg = lp.GlobalArg("A", dtype=scalar_type, shape=c_shape)
    varexp = gem.Variable("A", c_shape)
    expressions = [expression(gem.view(varexp, *slices)) for slices in slicez]
    return funarg, prune(expressions)
Esempio n. 24
0
    def __init__(self, scalar_type=None, interior_facet=False):
        """Initialise a kernel builder.

        :arg interior_facet: kernel accesses two cells
        """
        if scalar_type is None:
            from tsfc.parameters import SCALAR_TYPE
            scalar_type = SCALAR_TYPE
        super(KernelBuilderBase, self).__init__(scalar_type=scalar_type,
                                                interior_facet=interior_facet)

        # Cell orientation
        if self.interior_facet:
            cell_orientations = gem.Variable("cell_orientations", (2, ))
            self._cell_orientations = (gem.Indexed(cell_orientations, (0, )),
                                       gem.Indexed(cell_orientations, (1, )))
        else:
            cell_orientations = gem.Variable("cell_orientations", (1, ))
            self._cell_orientations = (gem.Indexed(cell_orientations, (0, )), )
Esempio n. 25
0
    def __init__(self, scalar_type, interior_facet=False):
        """Initialise a kernel builder.

        :arg interior_facet: kernel accesses two cells
        """
        super(KernelBuilderBase, self).__init__(scalar_type=scalar_type,
                                                interior_facet=interior_facet)

        # Cell orientation
        if self.interior_facet:
            shape = (2,)
            cell_orientations = gem.Variable("cell_orientations", shape)
            self._cell_orientations = (gem.Indexed(cell_orientations, (0,)),
                                       gem.Indexed(cell_orientations, (1,)))
        else:
            shape = (1,)
            cell_orientations = gem.Variable("cell_orientations", shape)
            self._cell_orientations = (gem.Indexed(cell_orientations, (0,)),)
        self.cell_orientations_loopy_arg = lp.GlobalArg("cell_orientations", dtype=numpy.int32, shape=shape)
Esempio n. 26
0
 def transpose(expr, rank):
     assert not expr.free_indices
     assert 0 <= rank < len(expr.shape)
     if rank == 0:
         return expr
     else:
         indices = tuple(gem.Index(extent=extent) for extent in expr.shape)
         transposed_indices = indices[rank:] + indices[:rank]
         return gem.ComponentTensor(gem.Indexed(expr, indices),
                                    transposed_indices)
Esempio n. 27
0
def select_hdiv_transformer(element):
    # Assume: something x interval
    assert len(element.factors) == 2
    assert element.factors[1].cell.get_shape() == LINE

    # Globally consistent edge orientations of the reference
    # quadrilateral: rightward horizontally, upward vertically.
    # Their rotation by 90 degrees anticlockwise is interpreted as the
    # positive direction for normal vectors.
    ks = tuple(fe.formdegree for fe in element.factors)
    if ks == (0, 1):
        # Make the scalar value the leftward-pointing normal on the
        # y-aligned edges.
        return lambda v: [gem.Product(gem.Literal(-1), v), gem.Zero()]
    elif ks == (1, 0):
        # Make the scalar value the upward-pointing normal on the
        # x-aligned edges.
        return lambda v: [gem.Zero(), v]
    elif ks == (2, 0):
        # Same for 3D, so z-plane.
        return lambda v: [gem.Zero(), gem.Zero(), v]
    elif ks == (1, 1):
        if element.mapping == "contravariant piola":
            # Pad the 2-vector normal on the "base" cell into a
            # 3-vector, maintaining direction.
            return lambda v: [
                gem.Indexed(v, (0, )),
                gem.Indexed(v, (1, )),
                gem.Zero()
            ]
        elif element.mapping == "covariant piola":
            # Rotate the 2-vector tangential component on the "base"
            # cell 90 degrees anticlockwise into a 3-vector and pad.
            return lambda v: [
                gem.Indexed(v, (1, )),
                gem.Product(gem.Literal(-1), gem.Indexed(v, (0, ))),
                gem.Zero()
            ]
        else:
            assert False, "Unexpected original mapping!"
    else:
        assert False, "Unexpected form degree combination!"
Esempio n. 28
0
def entity_support_dofs(elem, entity_dim):
    """Return the map of entity id to the degrees of freedom for which
    the corresponding basis functions take non-zero values.

    :arg elem: FInAT finite element
    :arg entity_dim: Dimension of the cell subentity.
    """
    if not hasattr(elem, "_entity_support_dofs"):
        elem._entity_support_dofs = {}
    cache = elem._entity_support_dofs
    try:
        return cache[entity_dim]
    except KeyError:
        pass

    beta = elem.get_indices()
    zeta = elem.get_value_indices()

    entity_cell = elem.cell.construct_subelement(entity_dim)
    quad = make_quadrature(entity_cell,
                           (2 * numpy.array(elem.degree)).tolist())

    eps = 1.e-8  # Is this a safe value?

    result = {}
    for f in elem.entity_dofs()[entity_dim].keys():
        # Tabulate basis functions on the facet
        vals, = itervalues(
            elem.basis_evaluation(0, quad.point_set, entity=(entity_dim, f)))
        # Integrate the square of the basis functions on the facet.
        ints = gem.IndexSum(
            gem.Product(
                gem.IndexSum(
                    gem.Product(gem.Indexed(vals, beta + zeta),
                                gem.Indexed(vals, beta + zeta)), zeta),
                quad.weight_expression), quad.point_set.indices)
        ints = aggressive_unroll(gem.ComponentTensor(ints,
                                                     beta)).array.flatten()
        result[f] = [dof for dof, i in enumerate(ints) if i > eps]

    cache[entity_dim] = result
    return result
Esempio n. 29
0
def point_evaluation_generic(fiat_element, order, refcoords, entity):
    # Coordinates on the reference entity (SymPy)
    esd, = refcoords.shape
    Xi = sp.symbols('X Y Z')[:esd]

    space_dimension = fiat_element.space_dimension()
    value_size = np.prod(fiat_element.value_shape(), dtype=int)
    fiat_result = fiat_element.tabulate(order, [Xi], entity)
    result = {}
    for alpha, fiat_table in fiat_result.items():
        if isinstance(fiat_table, Exception):
            result[alpha] = gem.Failure(
                (space_dimension, ) + fiat_element.value_shape(), fiat_table)
            continue

        # Convert SymPy expression to GEM
        mapper = gem.node.Memoizer(sympy2gem)
        mapper.bindings = {
            s: gem.Indexed(refcoords, (i, ))
            for i, s in enumerate(Xi)
        }
        gem_table = np.vectorize(mapper)(fiat_table)

        table_roll = gem_table.reshape(space_dimension, value_size).transpose()

        exprs = []
        for table in table_roll:
            exprs.append(gem.ListTensor(table.reshape(space_dimension)))
        if fiat_element.value_shape():
            beta = (gem.Index(extent=space_dimension), )
            zeta = tuple(
                gem.Index(extent=d) for d in fiat_element.value_shape())
            result[alpha] = gem.ComponentTensor(
                gem.Indexed(
                    gem.ListTensor(
                        np.array([gem.Indexed(expr, beta) for expr in exprs
                                  ]).reshape(fiat_element.value_shape())),
                    zeta), beta + zeta)
        else:
            expr, = exprs
            result[alpha] = expr
    return result
Esempio n. 30
0
File: fem.py Progetto: knut0815/tsfc
def fiat_to_ufl(fiat_dict, order):
    # All derivative multiindices must be of the same dimension.
    dimension, = set(len(alpha) for alpha in fiat_dict.keys())

    # All derivative tables must have the same shape.
    shape, = set(table.shape for table in fiat_dict.values())
    sigma = tuple(gem.Index(extent=extent) for extent in shape)

    # Convert from FIAT to UFL format
    eye = numpy.eye(dimension, dtype=int)
    tensor = numpy.empty((dimension, ) * order, dtype=object)
    for multiindex in numpy.ndindex(tensor.shape):
        alpha = tuple(eye[multiindex, :].sum(axis=0))
        tensor[multiindex] = gem.Indexed(fiat_dict[alpha], sigma)
    delta = tuple(gem.Index(extent=dimension) for _ in range(order))
    if order > 0:
        tensor = gem.Indexed(gem.ListTensor(tensor), delta)
    else:
        tensor = tensor[()]
    return gem.ComponentTensor(tensor, sigma + delta)