def sum(self, o, *operands):
        code = {}
        # Loop operands that has to be summend.
        for op in operands:
            # If entries does already exist we can add the code,
            # otherwise just dump them in the element tensor.
            for key, val in sorted(op.items()):
                if key in code:
                    code[key].append(val)
                else:
                    code[key] = [val]

        # Add sums and group if necessary.
        for key, val in sorted_by_key(code):
            if len(val) > 1:
                code[key] = create_sum(val)
            elif val:
                code[key] = val[0]
            else:
                error("Where did the values go?")
            # If value is zero just ignore it.
            if abs(code[key].val) < format["epsilon"]:
                del code[key]

        return code
    def sum(self, o, *operands):
        code = {}
        # Loop operands that has to be summend.
        for op in operands:
            # If entries does already exist we can add the code,
            # otherwise just dump them in the element tensor.
            for key, val in sorted(op.items()):
                if key in code:
                    code[key].append(val)
                else:
                    code[key] = [val]

        # Add sums and group if necessary.
        for key, val in sorted_by_key(code):
            if len(val) > 1:
                code[key] = create_sum(val)
            elif val:
                code[key] = val[0]
            else:
                error("Where did the values go?")
            # If value is zero just ignore it.
            if abs(code[key].val) < format["epsilon"]:
                del code[key]

        return code
    def sum(self, o, *operands):
        #print("Visiting Sum: " + repr(o) + "\noperands: " + "\n".join(map(repr, operands)))

        code = {}
        # Loop operands that has to be summend.
        for op in operands:
            # If entries does already exist we can add the code, otherwise just
            # dump them in the element tensor.
            for key, val in op.items():
                if key in code:
                    code[key].append(val)
                else:
                    code[key] = [val]

        # Add sums and group if necessary.
        for key, val in code.items():
            if len(val) > 1:
                code[key] = create_sum(val)
            elif val:
                code[key] = val[0]
            else:
                error("Where did the values go?")
            # If value is zero just ignore it.
            if abs(code[key].val) < format["epsilon"]:
                del code[key]

        return code
示例#4
0
def _reduce_expression(expr, symbols, const_dict, f_name, use_expr_type=False):
    if use_expr_type:
        if expr not in const_dict:
            const_dict[expr] = len(const_dict)
        return create_symbol(f_name(const_dict[expr]), expr.t)
    # Only something to be done if we have more than one symbol.
    if len(symbols) > 1:
        sym_type = symbols[0].t
        # Create new symbol.
        if expr._prec == 2:
            new_sym = create_product(symbols)
        elif expr._prec == 3:
            new_sym = create_sum(symbols)
        if new_sym not in const_dict:
            const_dict[new_sym] = len(const_dict)
        s = create_symbol(f_name(const_dict[new_sym]), sym_type)
        return [s]
    return symbols
def _reduce_expression(expr, symbols, const_dict, f_name, use_expr_type=False):
    if use_expr_type:
        if expr not in const_dict:
            const_dict[expr] = len(const_dict)
        return create_symbol(f_name(const_dict[expr]), expr.t)
    # Only something to be done if we have more than one symbol.
    if len(symbols) > 1:
        sym_type = symbols[0].t
        # Create new symbol.
        if expr._prec == 2:
            new_sym = create_product(symbols)
        elif expr._prec == 3:
            new_sym = create_sum(symbols)
        if new_sym not in const_dict:
            const_dict[new_sym] = len(const_dict)
        s = create_symbol(f_name(const_dict[new_sym]), sym_type)
        return [s]
    return symbols
    def create_function(self, ufl_function, derivatives, component, local_comp,
                        local_offset, ffc_element, is_quad_element,
                        transformation, multiindices, tdim, gdim, avg):
        "Create code for basis functions, and update relevant tables of used basis."
        ffc_assert(
            ufl_function in self._function_replace_values,
            "Expecting ufl_function to have been mapped prior to this call.")

        # Prefetch formats to speed up code generation.
        f_transform = format["transform"]
        f_detJ = format["det(J)"]

        # Reset code
        code = []

        # Handle affine mappings.
        if transformation == "affine":
            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                # Create function name.
                function_name = self._create_function_name(
                    component, deriv, avg, is_quad_element, ufl_function,
                    ffc_element)
                if function_name:
                    # Add transformation if needed.
                    code.append(
                        self.__apply_transform(function_name, derivatives,
                                               multi, tdim, gdim))

        # Handle non-affine mappings.
        else:
            ffc_assert(
                avg is None,
                "Taking average is not supported for non-affine mappings.")

            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                if transformation in [
                        "covariant piola", "contravariant piola"
                ]:
                    for c in range(tdim):
                        function_name = self._create_function_name(
                            c + local_offset, deriv, avg, is_quad_element,
                            ufl_function, ffc_element)
                        if function_name:
                            # Multiply basis by appropriate transform.
                            if transformation == "covariant piola":
                                dxdX = create_symbol(
                                    f_transform("JINV", c, local_comp, tdim,
                                                gdim, self.restriction), GEO)
                                function_name = create_product(
                                    [dxdX, function_name])
                            elif transformation == "contravariant piola":
                                detJ = create_fraction(
                                    create_float(1),
                                    create_symbol(f_detJ(self.restriction),
                                                  GEO))
                                dXdx = create_symbol(
                                    f_transform("J", local_comp, c, gdim, tdim,
                                                self.restriction), GEO)
                                function_name = create_product(
                                    [detJ, dXdx, function_name])
                            # Add transformation if needed.
                            code.append(
                                self.__apply_transform(function_name,
                                                       derivatives, multi,
                                                       tdim, gdim))
                elif transformation == "double covariant piola":
                    # g_ij = (Jinv)_ki G_kl (Jinv)lj
                    i = local_comp // tdim
                    j = local_comp % tdim
                    for k in range(tdim):
                        for l in range(tdim):
                            # Create mapping and basis name.
                            function_name = self._create_function_name(
                                k * tdim + l + local_offset, deriv, avg,
                                is_quad_element, ufl_function, ffc_element)
                            J1 = create_symbol(
                                f_transform("JINV", k, i, tdim, gdim,
                                            self.restriction), GEO)
                            J2 = create_symbol(
                                f_transform("JINV", l, j, tdim, gdim,
                                            self.restriction), GEO)
                            function_name = create_product(
                                [J1, function_name, J2])
                            # Add transformation if needed.
                            code.append(
                                self.__apply_transform(function_name,
                                                       derivatives, multi,
                                                       tdim, gdim))
                elif transformation == "double contravariant piola":
                    # g_ij = (detJ)^(-2) J_ik G_kl J_jl
                    i = local_comp // tdim
                    j = local_comp % tdim
                    for k in range(tdim):
                        for l in range(tdim):
                            # Create mapping and basis name.
                            function_name = self._create_function_name(
                                k * tdim + l + local_offset, deriv, avg,
                                is_quad_element, ufl_function, ffc_element)
                            J1 = create_symbol(
                                f_transform("J", i, k, tdim, gdim,
                                            self.restriction), GEO)
                            J2 = create_symbol(
                                f_transform("J", j, l, tdim, gdim,
                                            self.restriction), GEO)
                            invdetJ = create_fraction(
                                create_float(1),
                                create_symbol(f_detJ(self.restriction), GEO))
                            function_name = create_product(
                                [invdetJ, invdetJ, J1, function_name, J2])
                            # Add transformation if needed.
                            code.append(
                                self.__apply_transform(function_name,
                                                       derivatives, multi,
                                                       tdim, gdim))
                else:
                    error("Transformation is not supported: ",
                          repr(transformation))

        if not code:
            return create_float(0.0)
        elif len(code) > 1:
            code = create_sum(code)
        else:
            code = code[0]

        return code
    def create_argument(self, ufl_argument, derivatives, component, local_comp,
                        local_offset, ffc_element, transformation,
                        multiindices, tdim, gdim, avg):
        "Create code for basis functions, and update relevant tables of used basis."

        # Prefetch formats to speed up code generation.
        f_transform = format["transform"]
        f_detJ = format["det(J)"]

        # Reset code
        code = {}

        # Affine mapping
        if transformation == "affine":
            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                # Create mapping and basis name.
                mapping, basis = self._create_mapping_basis(
                    component, deriv, avg, ufl_argument, ffc_element)
                if mapping not in code:
                    code[mapping] = []

                if basis is not None:
                    # Add transformation if needed.
                    code[mapping].append(
                        self.__apply_transform(basis, derivatives, multi, tdim,
                                               gdim))

        # Handle non-affine mappings.
        else:
            ffc_assert(
                avg is None,
                "Taking average is not supported for non-affine mappings.")

            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                if transformation in [
                        "covariant piola", "contravariant piola"
                ]:
                    for c in range(tdim):
                        # Create mapping and basis name.
                        mapping, basis = self._create_mapping_basis(
                            c + local_offset, deriv, avg, ufl_argument,
                            ffc_element)
                        if mapping not in code:
                            code[mapping] = []

                        if basis is not None:
                            # Multiply basis by appropriate transform.
                            if transformation == "covariant piola":
                                dxdX = create_symbol(
                                    f_transform("JINV", c, local_comp, tdim,
                                                gdim, self.restriction), GEO)
                                basis = create_product([dxdX, basis])
                            elif transformation == "contravariant piola":
                                detJ = create_fraction(
                                    create_float(1),
                                    create_symbol(f_detJ(self.restriction),
                                                  GEO))
                                dXdx = create_symbol(
                                    f_transform("J", local_comp, c, gdim, tdim,
                                                self.restriction), GEO)
                                basis = create_product([detJ, dXdx, basis])
                        # Add transformation if needed.
                        code[mapping].append(
                            self.__apply_transform(basis, derivatives, multi,
                                                   tdim, gdim))
                elif transformation == "double covariant piola":
                    # g_ij = (Jinv)_ki G_kl (Jinv)lj
                    i = local_comp // tdim
                    j = local_comp % tdim
                    for k in range(tdim):
                        for l in range(tdim):
                            # Create mapping and basis name.
                            mapping, basis = self._create_mapping_basis(
                                k * tdim + l + local_offset, deriv, avg,
                                ufl_argument, ffc_element)
                            if mapping not in code:
                                code[mapping] = []
                            if basis is not None:
                                J1 = create_symbol(
                                    f_transform("JINV", k, i, tdim, gdim,
                                                self.restriction), GEO)
                                J2 = create_symbol(
                                    f_transform("JINV", l, j, tdim, gdim,
                                                self.restriction), GEO)
                                basis = create_product([J1, basis, J2])
                                # Add transformation if needed.
                                code[mapping].append(
                                    self.__apply_transform(
                                        basis, derivatives, multi, tdim, gdim))
                elif transformation == "double contravariant piola":
                    # g_ij = (detJ)^(-2) J_ik G_kl J_jl
                    i = local_comp // tdim
                    j = local_comp % tdim
                    for k in range(tdim):
                        for l in range(tdim):
                            # Create mapping and basis name.
                            mapping, basis = self._create_mapping_basis(
                                k * tdim + l + local_offset, deriv, avg,
                                ufl_argument, ffc_element)
                            if mapping not in code:
                                code[mapping] = []
                            if basis is not None:
                                J1 = create_symbol(
                                    f_transform("J", i, k, gdim, tdim,
                                                self.restriction), GEO)
                                J2 = create_symbol(
                                    f_transform("J", j, l, gdim, tdim,
                                                self.restriction), GEO)
                                invdetJ = create_fraction(
                                    create_float(1),
                                    create_symbol(f_detJ(self.restriction),
                                                  GEO))
                                basis = create_product(
                                    [invdetJ, invdetJ, J1, basis, J2])
                                # Add transformation if needed.
                                code[mapping].append(
                                    self.__apply_transform(
                                        basis, derivatives, multi, tdim, gdim))
                else:
                    error("Transformation is not supported: " +
                          repr(transformation))

        # Add sums and group if necessary.
        for key, val in list(code.items()):
            if len(val) > 1:
                code[key] = create_sum(val)
            else:
                code[key] = val[0]

        return code
示例#8
0
def _extract_variables(val, basis_consts, ip_consts, geo_consts, t_set,
                       optimisation):
    f_G = format["geometry constant"]
    f_I = format["ip constant"]
    f_B = format["basis constant"]

    if val._prec == 0:
        return val
    elif val._prec == 1:
        if val.base_expr is None:
            return val
        new_base = _extract_variables(val.base_expr, basis_consts, ip_consts,
                                      geo_consts, t_set, optimisation)
        new_sym = create_symbol(val.v, val.t, new_base, val.base_op)
        if new_sym.t == BASIS:
            return _reduce_expression(new_sym, [], basis_consts, f_B, True)
        elif new_sym.t == IP:
            return _reduce_expression(new_sym, [], ip_consts, f_I, True)
        elif new_sym.t == GEO:
            return _reduce_expression(new_sym, [], geo_consts, f_G, True)
    # First handle child classes of product and sum.
    elif val._prec in (2, 3):
        new_vars = []
        for v in val.vrs:
            new_vars.append(
                _extract_variables(v, basis_consts, ip_consts, geo_consts,
                                   t_set, optimisation))
        if val._prec == 2:
            new_val = create_product(new_vars)
        if val._prec == 3:
            new_val = create_sum(new_vars)
    elif val._prec == 4:
        num = _extract_variables(val.num, basis_consts, ip_consts, geo_consts,
                                 t_set, optimisation)
        denom = _extract_variables(val.denom, basis_consts, ip_consts,
                                   geo_consts, t_set, optimisation)
        return create_fraction(num, denom)
    else:
        error("Unknown symbolic type: %s" % repr(val))

    # Sort variables of product and sum.
    b_c, i_c, g_c = [], [], []
    for v in new_val.vrs:
        if v.t == BASIS:
            if optimisation == "precompute_basis_const":
                b_c.append(v)
        elif v.t == IP:
            i_c.append(v)
        else:
            g_c.append(v)
    vrs = new_val.vrs[:]
    for v in g_c + i_c + b_c:
        vrs.remove(v)
    i_c.extend(_reduce_expression(new_val, g_c, geo_consts, f_G))
    vrs.extend(_reduce_expression(new_val, i_c, ip_consts, f_I))
    vrs.extend(_reduce_expression(new_val, b_c, basis_consts, f_B))

    #    print "b_c: "
    #    for b in b_c:
    #        print b
    #    print "basis"
    #    for k,v in basis_consts.items():
    #        print "k: ", k
    #        print "v: ", v
    #    print "geo"
    #    for k,v in geo_consts.items():
    #        print "k: ", k
    #        print "v: ", v
    #    print "ret val: ", val

    if len(vrs) > 1:
        if new_val._prec == 2:
            new_object = create_product(vrs)
        elif new_val._prec == 3:
            new_object = create_sum(vrs)
        else:
            error("Must have product or sum here: %s" % repr(new_val))
        if new_object.t == BASIS:
            if optimisation == "precompute_ip_const":
                return new_object
            elif optimisation == "precompute_basis_const":
                return _reduce_expression(new_object, [], basis_consts, f_B,
                                          True)
        elif new_object.t == IP:
            return _reduce_expression(new_object, [], ip_consts, f_I, True)
        elif new_object.t == GEO:
            return _reduce_expression(new_object, [], geo_consts, f_G, True)
    return vrs[0]
    def create_function(self, ufl_function, derivatives, component, local_comp,
                        local_offset, ffc_element, is_quad_element,
                        transformation, multiindices, tdim, gdim, avg):
        "Create code for basis functions, and update relevant tables of used basis."
        ffc_assert(
            ufl_function in self._function_replace_values,
            "Expecting ufl_function to have been mapped prior to this call.")

        # Prefetch formats to speed up code generation.
        f_transform = format["transform"]
        f_detJ = format["det(J)"]

        # Reset code
        code = []

        # Handle affine mappings.
        if transformation == "affine":
            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                # Create function name.
                function_name = self._create_function_name(
                    component, deriv, avg, is_quad_element, ufl_function,
                    ffc_element)
                if function_name:
                    # Add transformation if needed.
                    code.append(
                        self.__apply_transform(function_name, derivatives,
                                               multi, tdim, gdim))

        # Handle non-affine mappings.
        else:
            ffc_assert(
                avg is None,
                "Taking average is not supported for non-affine mappings.")

            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                for c in range(tdim):
                    function_name = self._create_function_name(
                        c + local_offset, deriv, avg, is_quad_element,
                        ufl_function, ffc_element)
                    if function_name:
                        # Multiply basis by appropriate transform.
                        if transformation == "covariant piola":
                            dxdX = create_symbol(
                                f_transform("JINV", c, local_comp, tdim, gdim,
                                            self.restriction),
                                GEO,
                                loop_index=[c * gdim + local_comp],
                                iden="K%s" % _choose_map(self.restriction))
                            function_name = create_product(
                                [dxdX, function_name])
                        elif transformation == "contravariant piola":
                            detJ = create_fraction(
                                create_float(1),
                                create_symbol(f_detJ(self.restriction),
                                              GEO,
                                              iden=f_detJ(self.restriction)))
                            dXdx = create_symbol(f_transform("J", local_comp, c, gdim, tdim, self.restriction), GEO, \
                                        loop_index=[local_comp*tdim + c], iden="J%s" % _choose_map(self.restriction))
                            function_name = create_product(
                                [detJ, dXdx, function_name])
                        else:
                            error("Transformation is not supported: ",
                                  repr(transformation))

                        # Add transformation if needed.
                        code.append(
                            self.__apply_transform(function_name, derivatives,
                                                   multi, tdim, gdim))

        if not code:
            return create_float(0.0)
        elif len(code) > 1:
            code = create_sum(code)
        else:
            code = code[0]

        return code
    def create_argument(self, ufl_argument, derivatives, component, local_comp,
                        local_offset, ffc_element, transformation,
                        multiindices, tdim, gdim, avg):
        "Create code for basis functions, and update relevant tables of used basis."

        # Prefetch formats to speed up code generation.
        f_transform = format["transform"]
        f_detJ = format["det(J)"]

        # Reset code
        code = {}

        # Affine mapping
        if transformation == "affine":
            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                # Create mapping and basis name.
                mapping, basis = self._create_mapping_basis(
                    component, deriv, avg, ufl_argument, ffc_element)
                if isinstance(mapping, list):
                    for ma, ba in zip(mapping, basis):
                        if not ma in code:
                            code[ma] = []
                        if basis is not None:
                            # Add transformation if needed.
                            code[ma].append(
                                self.__apply_transform(ba, derivatives, multi,
                                                       tdim, gdim))
                else:
                    if not mapping in code:
                        code[mapping] = []
                    if basis is not None:
                        # Add transformation if needed.
                        code[mapping].append(
                            self.__apply_transform(basis, derivatives, multi,
                                                   tdim, gdim))

        # Handle non-affine mappings.
        else:
            ffc_assert(
                avg is None,
                "Taking average is not supported for non-affine mappings.")

            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                for c in range(tdim):
                    # Create mapping and basis name.
                    mapping, basis = self._create_mapping_basis(
                        c + local_offset, deriv, avg, ufl_argument,
                        ffc_element)
                    if not mapping in code:
                        code[mapping] = []

                    if basis is not None:
                        # Multiply basis by appropriate transform.
                        if transformation == "covariant piola":
                            dxdX = create_symbol(
                                f_transform("JINV", c, local_comp, tdim, gdim,
                                            self.restriction),
                                GEO,
                                loop_index=[c * gdim + local_comp],
                                iden="K%s" % _choose_map(self.restriction))
                            basis = create_product([dxdX, basis])
                        elif transformation == "contravariant piola":
                            detJ = create_fraction(create_float(1), \
                                        create_symbol(f_detJ(self.restriction), GEO, iden=f_detJ(self.restriction)))
                            dXdx = create_symbol(f_transform("J", local_comp, c, gdim, tdim, self.restriction), GEO, \
                                        loop_index=[local_comp*tdim + c], iden="J%s" % _choose_map(self.restriction))
                            basis = create_product([detJ, dXdx, basis])
                        else:
                            error("Transformation is not supported: " +
                                  repr(transformation))

                        # Add transformation if needed.
                        code[mapping].append(
                            self.__apply_transform(basis, derivatives, multi,
                                                   tdim, gdim))

        # Add sums and group if necessary.
        for key, val in list(code.items()):
            if len(val) > 1:
                code[key] = create_sum(val)
            else:
                code[key] = val[0]

        return code
def _extract_variables(val, basis_consts, ip_consts, geo_consts, t_set, optimisation):
    f_G = format["geometry constant"]
    f_I = format["ip constant"]
    f_B = format["basis constant"]

    if val._prec == 0:
        return val
    elif val._prec == 1:
        if val.base_expr is None:
            return val
        new_base = _extract_variables(val.base_expr, basis_consts, ip_consts, geo_consts, t_set, optimisation)
        new_sym = create_symbol(val.v, val.t, new_base, val.base_op)
        if new_sym.t == BASIS:
            return _reduce_expression(new_sym, [], basis_consts, f_B, True)
        elif new_sym.t == IP:
            return _reduce_expression(new_sym, [], ip_consts, f_I, True)
        elif new_sym.t == GEO:
            return _reduce_expression(new_sym, [], geo_consts, f_G, True)
    # First handle child classes of product and sum.
    elif val._prec in (2, 3):
        new_vars = []
        for v in val.vrs:
            new_vars.append(_extract_variables(v, basis_consts, ip_consts, geo_consts, t_set, optimisation))
        if val._prec == 2:
            new_val = create_product(new_vars)
        if val._prec == 3:
            new_val = create_sum(new_vars)
    elif val._prec == 4:
        num = _extract_variables(val.num, basis_consts, ip_consts, geo_consts, t_set, optimisation)
        denom = _extract_variables(val.denom, basis_consts, ip_consts, geo_consts, t_set, optimisation)
        return create_fraction(num, denom)
    else:
        error("Unknown symbolic type: %s" % repr(val))

    # Sort variables of product and sum.
    b_c, i_c, g_c = [], [], []
    for v in new_val.vrs:
        if v.t == BASIS:
            if optimisation == "precompute_basis_const":
                b_c.append(v)
        elif v.t == IP:
            i_c.append(v)
        else:
            g_c.append(v)
    vrs = new_val.vrs[:]
    for v in g_c + i_c + b_c:
        vrs.remove(v)
    i_c.extend(_reduce_expression(new_val, g_c, geo_consts, f_G))
    vrs.extend(_reduce_expression(new_val, i_c, ip_consts, f_I))
    vrs.extend(_reduce_expression(new_val, b_c, basis_consts, f_B))

#    print "b_c: "
#    for b in b_c:
#        print b
#    print "basis"
#    for k,v in basis_consts.items():
#        print "k: ", k
#        print "v: ", v
#    print "geo"
#    for k,v in geo_consts.items():
#        print "k: ", k
#        print "v: ", v
#    print "ret val: ", val

    if len(vrs) > 1:
        if new_val._prec == 2:
            new_object = create_product(vrs)
        elif new_val._prec == 3:
            new_object = create_sum(vrs)
        else:
            error("Must have product or sum here: %s" % repr(new_val))
        if new_object.t == BASIS:
            if optimisation == "precompute_ip_const":
                return new_object
            elif optimisation == "precompute_basis_const":
                return _reduce_expression(new_object, [], basis_consts, f_B, True)
        elif new_object.t == IP:
            return _reduce_expression(new_object, [], ip_consts, f_I, True)
        elif new_object.t == GEO:
            return _reduce_expression(new_object, [], geo_consts, f_G, True)
    return vrs[0]
    def create_function(self, ufl_function, derivatives, component, local_comp,
                        local_offset, ffc_element, is_quad_element,
                        transformation, multiindices, tdim, gdim, avg):
        "Create code for basis functions, and update relevant tables of used basis."
        ffc_assert(ufl_function in self._function_replace_values,
                   "Expecting ufl_function to have been mapped prior to this call.")

        # Prefetch formats to speed up code generation.
        f_transform = format["transform"]
        f_detJ = format["det(J)"]

        # Reset code
        code = []

        # Handle affine mappings.
        if transformation == "affine":
            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                # Create function name.
                function_name = self._create_function_name(component, deriv,
                                                           avg, is_quad_element,
                                                           ufl_function,
                                                           ffc_element)
                if function_name:
                    # Add transformation if needed.
                    code.append(self.__apply_transform(function_name,
                                                       derivatives, multi, tdim, gdim))

        # Handle non-affine mappings.
        else:
            ffc_assert(avg is None,
                       "Taking average is not supported for non-affine mappings.")

            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                if transformation in ["covariant piola",
                                      "contravariant piola"]:
                    for c in range(tdim):
                        function_name = self._create_function_name(c + local_offset, deriv, avg, is_quad_element, ufl_function, ffc_element)
                        if function_name:
                            # Multiply basis by appropriate transform.
                            if transformation == "covariant piola":
                                dxdX = create_symbol(f_transform("JINV", c,
                                                                 local_comp, tdim,
                                                                 gdim,
                                                                 self.restriction),
                                                     GEO)
                                function_name = create_product([dxdX, function_name])
                            elif transformation == "contravariant piola":
                                detJ = create_fraction(create_float(1),
                                                       create_symbol(f_detJ(self.restriction),
                                                                     GEO))
                                dXdx = create_symbol(f_transform("J", local_comp,
                                                                 c, gdim, tdim,
                                                                 self.restriction),
                                                     GEO)
                                function_name = create_product([detJ, dXdx,
                                                                function_name])
                            # Add transformation if needed.
                            code.append(self.__apply_transform(function_name,
                                                               derivatives, multi,
                                                               tdim, gdim))
                elif transformation == "double covariant piola":
                    # g_ij = (Jinv)_ki G_kl (Jinv)lj
                    i = local_comp // tdim
                    j = local_comp % tdim
                    for k in range(tdim):
                        for l in range(tdim):
                            # Create mapping and basis name.
                            function_name = self._create_function_name(
                                k * tdim + l + local_offset, deriv, avg,
                                is_quad_element, ufl_function, ffc_element)
                            J1 = create_symbol(
                                f_transform("JINV", k, i, tdim, gdim,
                                            self.restriction), GEO)
                            J2 = create_symbol(
                                f_transform("JINV", l, j, tdim, gdim,
                                            self.restriction), GEO)
                            function_name = create_product([J1, function_name,
                                                            J2])
                            # Add transformation if needed.
                            code.append(self.__apply_transform(
                                function_name, derivatives, multi, tdim, gdim))
                elif transformation == "double contravariant piola":
                    # g_ij = (detJ)^(-2) J_ik G_kl J_jl
                    i = local_comp // tdim
                    j = local_comp % tdim
                    for k in range(tdim):
                        for l in range(tdim):
                            # Create mapping and basis name.
                            function_name = self._create_function_name(
                                k * tdim + l + local_offset,
                                deriv, avg, is_quad_element,
                                ufl_function, ffc_element)
                            J1 = create_symbol(
                                f_transform("J", i, k, tdim, gdim,
                                            self.restriction), GEO)
                            J2 = create_symbol(
                                f_transform("J", j, l, tdim, gdim,
                                            self.restriction), GEO)
                            invdetJ = create_fraction(
                                create_float(1),
                                create_symbol(f_detJ(self.restriction), GEO))
                            function_name = create_product([invdetJ, invdetJ,
                                                            J1, function_name,
                                                            J2])
                            # Add transformation if needed.
                            code.append(self.__apply_transform(function_name,
                                                               derivatives,
                                                               multi, tdim,
                                                               gdim))
                else:
                    error("Transformation is not supported: ",
                          repr(transformation))

        if not code:
            return create_float(0.0)
        elif len(code) > 1:
            code = create_sum(code)
        else:
            code = code[0]

        return code
    def create_argument(self, ufl_argument, derivatives, component, local_comp,
                        local_offset, ffc_element, transformation,
                        multiindices, tdim, gdim, avg):
        "Create code for basis functions, and update relevant tables of used basis."

        # Prefetch formats to speed up code generation.
        f_transform = format["transform"]
        f_detJ = format["det(J)"]

        # Reset code
        code = {}

        # Affine mapping
        if transformation == "affine":
            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                # Create mapping and basis name.
                mapping, basis = self._create_mapping_basis(component, deriv,
                                                            avg, ufl_argument,
                                                            ffc_element)
                if mapping not in code:
                    code[mapping] = []

                if basis is not None:
                    # Add transformation if needed.
                    code[mapping].append(self.__apply_transform(basis,
                                                                derivatives,
                                                                multi, tdim,
                                                                gdim))

        # Handle non-affine mappings.
        else:
            ffc_assert(avg is None,
                       "Taking average is not supported for non-affine mappings.")

            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(tdim)]
                if not any(deriv):
                    deriv = []

                if transformation in ["covariant piola",
                                      "contravariant piola"]:
                    for c in range(tdim):
                        # Create mapping and basis name.
                        mapping, basis = self._create_mapping_basis(c + local_offset, deriv, avg, ufl_argument, ffc_element)
                        if mapping not in code:
                            code[mapping] = []

                        if basis is not None:
                            # Multiply basis by appropriate transform.
                            if transformation == "covariant piola":
                                dxdX = create_symbol(f_transform("JINV", c,
                                                                 local_comp, tdim,
                                                                 gdim,
                                                                 self.restriction),
                                                     GEO)
                                basis = create_product([dxdX, basis])
                            elif transformation == "contravariant piola":
                                detJ = create_fraction(create_float(1),
                                                       create_symbol(f_detJ(self.restriction), GEO))
                                dXdx = create_symbol(f_transform("J", local_comp,
                                                                 c, gdim, tdim,
                                                                 self.restriction),
                                                     GEO)
                                basis = create_product([detJ, dXdx, basis])
                        # Add transformation if needed.
                        code[mapping].append(self.__apply_transform(basis,
                                                                    derivatives,
                                                                    multi, tdim,
                                                                    gdim))
                elif transformation == "double covariant piola":
                    # g_ij = (Jinv)_ki G_kl (Jinv)lj
                    i = local_comp // tdim
                    j = local_comp % tdim
                    for k in range(tdim):
                        for l in range(tdim):
                            # Create mapping and basis name.
                            mapping, basis = self._create_mapping_basis(
                                k * tdim + l + local_offset,
                                deriv, avg, ufl_argument, ffc_element)
                            if mapping not in code:
                                code[mapping] = []
                            if basis is not None:
                                J1 = create_symbol(
                                    f_transform("JINV", k, i, tdim, gdim,
                                                self.restriction), GEO)
                                J2 = create_symbol(
                                    f_transform("JINV", l, j, tdim, gdim,
                                                 self.restriction), GEO)
                                basis = create_product([J1, basis, J2])
                                # Add transformation if needed.
                                code[mapping].append(
                                    self.__apply_transform(
                                        basis, derivatives, multi,
                                        tdim, gdim))
                elif transformation == "double contravariant piola":
                    # g_ij = (detJ)^(-2) J_ik G_kl J_jl
                    i = local_comp // tdim
                    j = local_comp % tdim
                    for k in range(tdim):
                        for l in range(tdim):
                            # Create mapping and basis name.
                            mapping, basis = self._create_mapping_basis(
                                k * tdim + l + local_offset,
                                deriv, avg, ufl_argument, ffc_element)
                            if mapping not in code:
                                code[mapping] = []
                            if basis is not None:
                                J1 = create_symbol(
                                    f_transform("J", i, k, gdim, tdim,
                                                self.restriction), GEO)
                                J2 = create_symbol(
                                    f_transform("J", j, l, gdim, tdim,
                                                self.restriction), GEO)
                                invdetJ = create_fraction(
                                    create_float(1),
                                    create_symbol(f_detJ(self.restriction),
                                                  GEO))
                                basis = create_product([invdetJ, invdetJ, J1,
                                                        basis, J2])
                                # Add transformation if needed.
                                code[mapping].append(
                                    self.__apply_transform(
                                        basis, derivatives, multi,
                                        tdim, gdim))
                else:
                    error("Transformation is not supported: " + repr(transformation))


        # Add sums and group if necessary.
        for key, val in list(code.items()):
            if len(val) > 1:
                code[key] = create_sum(val)
            else:
                code[key] = val[0]

        return code
    def create_argument(self, ufl_argument, derivatives, component, local_comp,
                        local_offset, ffc_element, transformation, multiindices,
                        tdim, gdim, avg):
        "Create code for basis functions, and update relevant tables of used basis."
        ffc_assert(ufl_argument in self._function_replace_values, "Expecting ufl_argument to have been mapped prior to this call.")

        # Prefetch formats to speed up code generation.
        f_transform     = format["transform"]
        f_detJ          = format["det(J)"]

        # Reset code
        code = {}

        # Affine mapping
        if transformation == "affine":
            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(self.tdim)]
                if not any(deriv):
                    deriv = []

                # Create mapping and basis name.
                mapping, basis = self._create_mapping_basis(component, deriv, avg, ufl_argument, ffc_element)
                if not mapping in code:
                    code[mapping] = []

                if basis is not None:
                    # Add transformation if needed.
                    code[mapping].append(self.__apply_transform(basis, derivatives, multi, tdim, gdim))

        # Handle non-affine mappings.
        else:
            ffc_assert(avg is None, "Taking average is not supported for non-affine mappings.")

            # Loop derivatives and get multi indices.
            for multi in multiindices:
                deriv = [multi.count(i) for i in range(self.tdim)]
                if not any(deriv):
                    deriv = []

                for c in range(self.tdim):
                    # Create mapping and basis name.
                    mapping, basis = self._create_mapping_basis(c + local_offset, deriv, avg, ufl_argument, ffc_element)
                    if not mapping in code:
                        code[mapping] = []

                    if basis is not None:
                        # Multiply basis by appropriate transform.
                        if transformation == "covariant piola":
                            dxdX = create_symbol(f_transform("JINV", c, local_comp, tdim, gdim, self.restriction), GEO)
                            basis = create_product([dxdX, basis])
                        elif transformation == "contravariant piola":
                            detJ = create_fraction(create_float(1), create_symbol(f_detJ(self.restriction), GEO))
                            dXdx = create_symbol(f_transform("J", local_comp, c, gdim, tdim, self.restriction), GEO)
                            basis = create_product([detJ, dXdx, basis])
                        else:
                            error("Transformation is not supported: " + repr(transformation))

                        # Add transformation if needed.
                        code[mapping].append(self.__apply_transform(basis, derivatives, multi, tdim, gdim))

        # Add sums and group if necessary.
        for key, val in code.items():
            if len(val) > 1:
                code[key] = create_sum(val)
            else:
                code[key] = val[0]

        return code