Exemple #1
0
    def __new__(cls, a, b):
        # Conversion
        a = as_ufl(a)
        b = as_ufl(b)

        # Type checking
        if not is_true_ufl_scalar(a):
            error("Cannot take the power of a non-scalar expression %s." %
                  ufl_err_str(a))
        if not is_true_ufl_scalar(b):
            error("Cannot raise an expression to a non-scalar power %s." %
                  ufl_err_str(b))

        # Simplification
        if isinstance(a, ScalarValue) and isinstance(b, ScalarValue):
            return as_ufl(a._value**b._value)
        if isinstance(b, Zero):
            return IntValue(1)
        if isinstance(a, Zero) and isinstance(b, ScalarValue):
            if isinstance(b, ComplexValue):
                error("Cannot raise zero to a complex power.")
            bf = float(b)
            if bf < 0:
                error("Division by zero, cannot raise 0 to a negative power.")
            else:
                return zero()
        if isinstance(b, ScalarValue) and b._value == 1:
            return a

        # Construction
        self = Operator.__new__(cls)
        self._init(a, b)
        return self
Exemple #2
0
 def __getitem__(self, key):
     if key == ():
         # So that one doesn't have to special case indexing of
         # expressions without shape.
         return self
     error(
         "Attempting to index with %s, but object is already indexed: %s" %
         (ufl_err_str(key), ufl_err_str(self)))
Exemple #3
0
    def __init__(self, expression, multiindex):
        # Store operands
        Operator.__init__(self, (expression, multiindex))

        # Error checking
        if not isinstance(expression, Expr):
            error("Expecting Expr instance, not %s." % ufl_err_str(expression))
        if not isinstance(multiindex, MultiIndex):
            error("Expecting MultiIndex instance, not %s." %
                  ufl_err_str(multiindex))

        shape = expression.ufl_shape

        # Error checking
        if len(shape) != len(multiindex):
            error("Invalid number of indices (%d) for tensor "
                  "expression of rank %d:\n\t%s\n" %
                  (len(multiindex), len(
                      expression.ufl_shape), ufl_err_str(expression)))
        if any(
                int(di) >= int(si) or int(di) < 0
                for si, di in zip(shape, multiindex)
                if isinstance(di, FixedIndex)):
            error("Fixed index out of range!")

        # Build tuples of free index ids and dimensions
        if 1:
            efi = expression.ufl_free_indices
            efid = expression.ufl_index_dimensions
            fi = list(zip(efi, efid))
            for pos, ind in enumerate(multiindex._indices):
                if isinstance(ind, Index):
                    fi.append((ind.count(), shape[pos]))
            fi = unique_sorted_indices(sorted(fi))
            if fi:
                fi, fid = zip(*fi)
            else:
                fi, fid = (), ()

        else:
            mfiid = [(ind.count(), shape[pos])
                     for pos, ind in enumerate(multiindex._indices)
                     if isinstance(ind, Index)]
            mfi, mfid = zip(*mfiid) if mfiid else ((), ())
            fi, fid = merge_unique_indices(expression.ufl_free_indices,
                                           expression.ufl_index_dimensions,
                                           mfi, mfid)

        # Cache free index and dimensions
        self.ufl_free_indices = fi
        self.ufl_index_dimensions = fid
Exemple #4
0
    def __new__(cls, a, b):
        # Checks
        ash, bsh = a.ufl_shape, b.ufl_shape
        if ash != bsh:
            error("Shapes do not match: %s and %s." % (ufl_err_str(a), ufl_err_str(b)))

        # Simplification
        if isinstance(a, Zero) or isinstance(b, Zero):
            fi, fid = merge_nonoverlapping_indices(a, b)
            return Zero((), fi, fid)
        elif ash == ():
            return a*b

        return CompoundTensorOperator.__new__(cls)
Exemple #5
0
    def __new__(cls, a, b):
        ash = a.ufl_shape
        bsh = b.ufl_shape

        # Checks
        if not (len(ash) == 1 and ash == bsh):
            error("Cross product requires arguments of rank 1, got %s and %s." % (
                ufl_err_str(a), ufl_err_str(b)))

        # Simplification
        if isinstance(a, Zero) or isinstance(b, Zero):
            fi, fid = merge_nonoverlapping_indices(a, b)
            return Zero(ash, fi, fid)

        return CompoundTensorOperator.__new__(cls)
Exemple #6
0
    def __new__(cls, a, b):
        ash = a.ufl_shape
        bsh = b.ufl_shape

        # Checks
        if not (len(ash) == 1 and ash == bsh):
            error("Cross product requires arguments of rank 1, got %s and %s." % (
                ufl_err_str(a), ufl_err_str(b)))

        # Simplification
        if isinstance(a, Zero) or isinstance(b, Zero):
            fi, fid = merge_nonoverlapping_indices(a, b)
            return Zero(ash, fi, fid)

        return CompoundTensorOperator.__new__(cls)
Exemple #7
0
    def __init__(self, expression, multiindex):
        # Store operands
        Operator.__init__(self, (expression, multiindex))

        # Error checking
        if not isinstance(expression, Expr):
            error("Expecting Expr instance, not %s." % ufl_err_str(expression))
        if not isinstance(multiindex, MultiIndex):
            error("Expecting MultiIndex instance, not %s." % ufl_err_str(multiindex))

        shape = expression.ufl_shape

        # Error checking
        if len(shape) != len(multiindex):
            error("Invalid number of indices (%d) for tensor "
                  "expression of rank %d:\n\t%s\n"
                  % (len(multiindex), len(expression.ufl_shape), ufl_err_str(expression)))
        if any(int(di) >= int(si)
               for si, di in zip(shape, multiindex)
               if isinstance(di, FixedIndex)):
            error("Fixed index out of range!")

        # Build tuples of free index ids and dimensions
        if 1:
            efi = expression.ufl_free_indices
            efid = expression.ufl_index_dimensions
            fi = list(zip(efi, efid))
            for pos, ind in enumerate(multiindex._indices):
                if isinstance(ind, Index):
                    fi.append((ind.count(), shape[pos]))
            fi = unique_sorted_indices(sorted(fi))
            if fi:
                fi, fid = zip(*fi)
            else:
                fi, fid = (), ()

        else:
            mfiid = [(ind.count(), shape[pos])
                     for pos, ind in enumerate(multiindex._indices)
                     if isinstance(ind, Index)]
            mfi, mfid = zip(*mfiid) if mfiid else ((), ())
            fi, fid = merge_unique_indices(expression.ufl_free_indices,
                                           expression.ufl_index_dimensions,
                                           mfi, mfid)

        # Cache free index and dimensions
        self.ufl_free_indices = fi
        self.ufl_index_dimensions = fid
Exemple #8
0
    def reference_grad(self, g):
        # d (grad_X(...(x)) / dx => grad_X(...(Argument(x.function_space()))
        o = g
        ngrads = 0
        while isinstance(o, ReferenceGrad):
            o, = o.ufl_operands
            ngrads += 1
        if not (isinstance(o, SpatialCoordinate)
                or isinstance(o.ufl_operands[0], FormArgument)):
            error("Expecting gradient of a FormArgument, not %s" %
                  ufl_err_str(o))

        def apply_grads(f):
            for i in range(ngrads):
                f = ReferenceGrad(f)
            return f

        # Find o among all w without any indexing, which makes this
        # easy
        for (w, v) in zip(self._w, self._v):
            if o == w and isinstance(v, ReferenceValue) and isinstance(
                    v.ufl_operands[0], FormArgument):
                # Case: d/dt [w + t v]
                return apply_grads(v)
        return self.independent_terminal(o)
Exemple #9
0
 def expr(self, x):
     """The default is a nonlinear operator not accepting any
     Arguments among its children."""
     if _expr_has_terminal_types(x, Argument):
         error("Found Argument in %s, this is an invalid expression." %
               ufl_err_str(x))
     return (x, set())
Exemple #10
0
    def division(self, x):
        "Return parts_of_numerator/denominator."

        # Get numerator and denominator
        numerator, denominator = x.ufl_operands

        # Check for Arguments in the denominator
        if _expr_has_terminal_types(denominator, Argument):
            error(
                "Found Argument in denominator of %s , this is an invalid expression."
                % ufl_err_str(x))

        # Visit numerator
        numerator_parts, provides = self.visit(numerator)

        # If numerator is zero, return zero. (No need to check whether
        # it provides too much, already checked by visit.)
        if isinstance(numerator_parts, Zero):
            return (zero_expr(x), set())

        # Reuse x if possible, otherwise reconstruct from (parts of)
        # numerator and denominator
        x = self.reuse_if_possible(x, numerator_parts, denominator)

        return (x, provides)
Exemple #11
0
    def __init__(self, name, left, right):
        left = as_ufl(left)
        right = as_ufl(right)

        Condition.__init__(self, (left, right))

        self._name = name

        if name in ('!=', '=='):
            # Since equals and not-equals are used for comparing
            # representations, we have to allow any shape here. The
            # scalar properties must be checked when used in
            # conditional instead!
            pass
        elif name in ('&&', '||'):
            # Binary operators acting on boolean expressions allow
            # only conditions
            for arg in (left, right):
                if not isinstance(arg, Condition):
                    error("Expecting a Condition, not %s." % ufl_err_str(arg))
        else:
            # Binary operators acting on non-boolean expressions allow
            # only scalars
            if left.ufl_shape != () or right.ufl_shape != ():
                error("Expecting scalar arguments.")
            if left.ufl_free_indices != () or right.ufl_free_indices != ():
                error("Expecting scalar arguments.")
Exemple #12
0
    def __init__(self, name, left, right):
        left = as_ufl(left)
        right = as_ufl(right)

        Condition.__init__(self, (left, right))

        self._name = name

        if name in ('!=', '=='):
            # Since equals and not-equals are used for comparing
            # representations, we have to allow any shape here. The
            # scalar properties must be checked when used in
            # conditional instead!
            pass
        elif name in ('&&', '||'):
            # Binary operators acting on boolean expressions allow
            # only conditions
            for arg in (left, right):
                if not isinstance(arg, Condition):
                    error("Expecting a Condition, not %s." % ufl_err_str(arg))
        else:
            # Binary operators acting on non-boolean expressions allow
            # only scalars
            if left.ufl_shape != () or right.ufl_shape != ():
                error("Expecting scalar arguments.")
            if left.ufl_free_indices != () or right.ufl_free_indices != ():
                error("Expecting scalar arguments.")
Exemple #13
0
    def __new__(cls, a, b):
        # Conversion
        a = as_ufl(a)
        b = as_ufl(b)

        # Type checking
        # Make sure everything is scalar
        if a.ufl_shape or b.ufl_shape:
            error("Product can only represent products of scalars, "
                  "got\n\t%s\nand\n\t%s" % (ufl_err_str(a), ufl_err_str(b)))

        # Simplification
        if isinstance(a, Zero) or isinstance(b, Zero):
            # Got any zeros? Return zero.
            fi, fid = merge_unique_indices(a.ufl_free_indices,
                                           a.ufl_index_dimensions,
                                           b.ufl_free_indices,
                                           b.ufl_index_dimensions)
            return Zero((), fi, fid)
        sa = isinstance(a, ScalarValue)
        sb = isinstance(b, ScalarValue)
        if sa and sb:  # const * const = const
            # FIXME: Handle free indices like with zero? I think
            # IntValue may be index annotated now?
            return as_ufl(a._value * b._value)
        elif sa:  # 1 * b = b
            if a._value == 1:
                return b
            # a, b = a, b
        elif sb:  # a * 1 = a
            if b._value == 1:
                return a
            a, b = b, a
        # elif a == b: # a * a = a**2 # TODO: Why? Maybe just remove this?
        #    if not a.ufl_free_indices:
        #        return a**2
        else:  # a * b = b * a
            # Sort operands in a semi-canonical order
            # (NB! This is fragile! Small changes here can have large effects.)
            a, b = sorted_expr((a, b))

        # Construction
        self = Operator.__new__(cls)
        self._init(a, b)
        return self
Exemple #14
0
    def __new__(cls, a, b):
        # Checks
        ash, bsh = a.ufl_shape, b.ufl_shape
        if ash != bsh:
            error("Shapes do not match: %s and %s." % (ufl_err_str(a), ufl_err_str(b)))

        # Simplification
        if isinstance(a, Zero) or isinstance(b, Zero):
            fi, fid = merge_nonoverlapping_indices(a, b)
            return Zero((), fi, fid)
        elif ash == ():
            return a * Conj(b)
        # sort operands for unique representation,
        # must be independent of various counts etc.
        # as explained in cmp_expr
        if (a, b) != tuple(sorted_expr((a, b))):
            return Conj(Inner(b, a))

        return CompoundTensorOperator.__new__(cls)
Exemple #15
0
    def __new__(cls, a, b):
        # Checks
        ash, bsh = a.ufl_shape, b.ufl_shape
        if ash != bsh:
            error("Shapes do not match: %s and %s." % (ufl_err_str(a), ufl_err_str(b)))

        # Simplification
        if isinstance(a, Zero) or isinstance(b, Zero):
            fi, fid = merge_nonoverlapping_indices(a, b)
            return Zero((), fi, fid)
        elif ash == ():
            return a*Conj(b)
        # sort operands for unique representation,
        # must be independent of various counts etc.
        # as explained in cmp_expr
        if (a, b) != tuple(sorted_expr((a, b))):
            return Conj(Inner(b, a))

        return CompoundTensorOperator.__new__(cls)
Exemple #16
0
    def __new__(cls, summand, index):
        # Error checks
        if not isinstance(summand, Expr):
            error("Expecting Expr instance, got %s" % ufl_err_str(summand))
        if not isinstance(index, MultiIndex):
            error("Expecting MultiIndex instance, got %s" % ufl_err_str(index))
        if len(index) != 1:
            error("Expecting a single Index but got %d." % len(index))

        # Simplification to zero
        if isinstance(summand, Zero):
            sh = summand.ufl_shape
            j, = index
            fi = summand.ufl_free_indices
            fid = summand.ufl_index_dimensions
            pos = fi.index(j.count())
            fi = fi[:pos] + fi[pos + 1:]
            fid = fid[:pos] + fid[pos + 1:]
            return Zero(sh, fi, fid)

        return Operator.__new__(cls)
Exemple #17
0
    def __new__(cls, summand, index):
        # Error checks
        if not isinstance(summand, Expr):
            error("Expecting Expr instance, got %s" % ufl_err_str(summand))
        if not isinstance(index, MultiIndex):
            error("Expecting MultiIndex instance, got %s" % ufl_err_str(index))
        if len(index) != 1:
            error("Expecting a single Index but got %d." % len(index))

        # Simplification to zero
        if isinstance(summand, Zero):
            sh = summand.ufl_shape
            j, = index
            fi = summand.ufl_free_indices
            fid = summand.ufl_index_dimensions
            pos = fi.index(j.count())
            fi = fi[:pos] + fi[pos+1:]
            fid = fid[:pos] + fid[pos+1:]
            return Zero(sh, fi, fid)

        return Operator.__new__(cls)
Exemple #18
0
    def __call__(self, *args, **kwargs):
        """UFL form operator: Evaluate form by replacing arguments and
        coefficients.

        Replaces form.arguments() with given positional arguments in
        same number and ordering. Number of positional arguments must
        be 0 or equal to the number of Arguments in the form.

        The optional keyword argument coefficients can be set to a dict
        to replace Coefficients with expressions of matching shapes.

        Example:

          V = FiniteElement("CG", triangle, 1)
          v = TestFunction(V)
          u = TrialFunction(V)
          f = Coefficient(V)
          g = Coefficient(V)
          a = g*inner(grad(u), grad(v))*dx
          M = a(f, f, coefficients={ g: 1 })

        Is equivalent to M == grad(f)**2*dx.

        """
        repdict = {}

        if args:
            arguments = self.arguments()
            if len(arguments) != len(args):
                error("Need %d arguments to form(), got %d." %
                      (len(arguments), len(args)))
            repdict.update(zip(arguments, args))

        coefficients = kwargs.pop("coefficients")
        if kwargs:
            error("Unknown kwargs %s." % str(list(kwargs)))

        if coefficients is not None:
            coeffs = self.coefficients()
            for f in coefficients:
                if f in coeffs:
                    repdict[f] = coefficients[f]
                else:
                    warning("Coefficient %s is not in form." % ufl_err_str(f))
        if repdict:
            from ufl.formoperators import replace
            return replace(self, repdict)
        else:
            return self
Exemple #19
0
    def __call__(self, *args, **kwargs):
        """UFL form operator: Evaluate form by replacing arguments and
        coefficients.

        Replaces form.arguments() with given positional arguments in
        same number and ordering. Number of positional arguments must
        be 0 or equal to the number of Arguments in the form.

        The optional keyword argument coefficients can be set to a dict
        to replace Coefficients with expressions of matching shapes.

        Example:

          V = FiniteElement("CG", triangle, 1)
          v = TestFunction(V)
          u = TrialFunction(V)
          f = Coefficient(V)
          g = Coefficient(V)
          a = g*inner(grad(u), grad(v))*dx
          M = a(f, f, coefficients={ g: 1 })

        Is equivalent to M == grad(f)**2*dx.

        """
        repdict = {}

        if args:
            arguments = self.arguments()
            if len(arguments) != len(args):
                error("Need %d arguments to form(), got %d." % (len(arguments),
                                                                len(args)))
            repdict.update(zip(arguments, args))

        coefficients = kwargs.pop("coefficients")
        if kwargs:
            error("Unknown kwargs %s." % str(list(kwargs)))

        if coefficients is not None:
            coeffs = self.coefficients()
            for f in coefficients:
                if f in coeffs:
                    repdict[f] = coefficients[f]
                else:
                    warning("Coefficient %s is not in form." % ufl_err_str(f))
        if repdict:
            from ufl.formoperators import replace
            return replace(self, repdict)
        else:
            return self
Exemple #20
0
    def reference_grad(self, g):
        # d (grad_X(...(x)) / dx => grad_X(...(Argument(x.function_space()))
        o = g
        ngrads = 0
        while isinstance(o, ReferenceGrad):
            o, = o.ufl_operands
            ngrads += 1
        if not (isinstance(o, SpatialCoordinate) or isinstance(o.ufl_operands[0], FormArgument)):
            error("Expecting gradient of a FormArgument, not %s" % ufl_err_str(o))

        def apply_grads(f):
            for i in range(ngrads):
                f = ReferenceGrad(f)
            return f

        # Find o among all w without any indexing, which makes this
        # easy
        for (w, v) in zip(self._w, self._v):
            if o == w and isinstance(v, ReferenceValue) and isinstance(v.ufl_operands[0], FormArgument):
                # Case: d/dt [w + t v]
                return apply_grads(v)
        return self.independent_terminal(o)
Exemple #21
0
def _handle_derivative_arguments(form, coefficient, argument):
    # Wrap single coefficient in tuple for uniform treatment below
    if isinstance(coefficient, (list, tuple, ListTensor)):
        coefficients = tuple(coefficient)
    else:
        coefficients = (coefficient,)

    if argument is None:
        # Try to create argument if not provided
        if not all(isinstance(c, Coefficient) for c in coefficients):
            error("Can only create arguments automatically for non-indexed coefficients.")

        # Get existing arguments from form and position the new one
        # with the next argument number
        if isinstance(form, Form):
            form_arguments = form.arguments()
        else:
            # To handle derivative(expression), which is at least used
            # in tests. Remove?
            form_arguments = extract_arguments(form)

        numbers = sorted(set(arg.number() for arg in form_arguments))
        number = max(numbers + [-1]) + 1

        # Don't know what to do with parts, let the user sort it out
        # in that case
        parts = set(arg.part() for arg in form_arguments)
        if len(parts - {None}) != 0:
            error("Not expecting parts here, provide your own arguments.")
        part = None

        # Create argument and split it if in a mixed space
        function_spaces = [c.ufl_function_space() for c in coefficients]
        domains = [fs.ufl_domain() for fs in function_spaces]
        elements = [fs.ufl_element() for fs in function_spaces]
        if len(function_spaces) == 1:
            arguments = (Argument(function_spaces[0], number, part),)
        else:
            # Create in mixed space over assumed (for now) same domain
            assert all(fs.ufl_domain() == domains[0] for fs in function_spaces)
            elm = MixedElement(*elements)
            fs = FunctionSpace(domains[0], elm)
            arguments = split(Argument(fs, number, part))
    else:
        # Wrap single argument in tuple for uniform treatment below
        if isinstance(argument, (list, tuple)):
            arguments = tuple(argument)
        else:
            n = len(coefficients)
            if n == 1:
                arguments = (argument,)
            else:
                if argument.ufl_shape == (n,):
                    arguments = tuple(argument[i] for i in range(n))
                else:
                    arguments = split(argument)

    # Build mapping from coefficient to argument
    m = {}
    for (c, a) in zip(coefficients, arguments):
        if c.ufl_shape != a.ufl_shape:
            error("Coefficient and argument shapes do not match!")
        if isinstance(c, Coefficient) or isinstance(c, SpatialCoordinate):
            m[c] = a
        else:
            if not isinstance(c, Indexed):
                error("Invalid coefficient type for %s" % ufl_err_str(c))
            f, i = c.ufl_operands
            if not isinstance(f, Coefficient):
                error("Expecting an indexed coefficient, not %s" % ufl_err_str(f))
            if not (isinstance(i, MultiIndex) and all(isinstance(j, FixedIndex) for j in i)):
                error("Expecting one or more fixed indices, not %s" % ufl_err_str(i))
            i = tuple(int(j) for j in i)
            if f not in m:
                m[f] = {}
            m[f][i] = a

    # Merge coefficient derivatives (arguments) based on indices
    for c, p in m.items():
        if isinstance(p, dict):
            a = zero_lists(c.ufl_shape)
            for i, g in p.items():
                set_list_item(a, i, g)
            m[c] = as_tensor(a)

    # Wrap and return generic tuples
    items = sorted(m.items(), key=lambda x: x[0].count())
    coefficients = ExprList(*[item[0] for item in items])
    arguments = ExprList(*[item[1] for item in items])
    return coefficients, arguments
Exemple #22
0
def expecting_terminal(v):
    error("Expecting Terminal instance, not %s." % ufl_err_str(v))
Exemple #23
0
def expecting_true_ufl_scalar(v):
    error("Expecting UFL scalar expression with no free indices, not %s." %
          ufl_err_str(v))
Exemple #24
0
def expecting_python_scalar(v):
    error("Expecting Python scalar, not %s." % ufl_err_str(v))
Exemple #25
0
def expecting_expr(v):
    error("Expecting Expr instance, not %s." % ufl_err_str(v))
Exemple #26
0
    def grad(self, g):
        # If we hit this type, it has already been propagated to a
        # coefficient (or grad of a coefficient), # FIXME: Assert
        # this!  so we need to take the gradient of the variation or
        # return zero.  Complications occur when dealing with
        # derivatives w.r.t. single components...

        # Figure out how many gradients are around the inner terminal
        ngrads = 0
        o = g
        while isinstance(o, Grad):
            o, = o.ufl_operands
            ngrads += 1
        if not isinstance(o, FormArgument):
            error("Expecting gradient of a FormArgument, not %s" % ufl_err_str(o))

        def apply_grads(f):
            for i in range(ngrads):
                f = Grad(f)
            return f

        # Find o among all w without any indexing, which makes this
        # easy
        for (w, v) in zip(self._w, self._v):
            if o == w and isinstance(v, FormArgument):
                # Case: d/dt [w + t v]
                return apply_grads(v)

        # If o is not among coefficient derivatives, return do/dw=0
        gprimesum = Zero(g.ufl_shape)

        def analyse_variation_argument(v):
            # Analyse variation argument
            if isinstance(v, FormArgument):
                # Case: d/dt [w[...] + t v]
                vval, vcomp = v, ()
            elif isinstance(v, Indexed):
                # Case: d/dt [w + t v[...]]
                # Case: d/dt [w[...] + t v[...]]
                vval, vcomp = v.ufl_operands
                vcomp = tuple(vcomp)
            else:
                error("Expecting argument or component of argument.")
            if not all(isinstance(k, FixedIndex) for k in vcomp):
                error("Expecting only fixed indices in variation.")
            return vval, vcomp

        def compute_gprimeterm(ngrads, vval, vcomp, wshape, wcomp):
            # Apply gradients directly to argument vval, and get the
            # right indexed scalar component(s)
            kk = indices(ngrads)
            Dvkk = apply_grads(vval)[vcomp+kk]
            # Place scalar component(s) Dvkk into the right tensor
            # positions
            if wshape:
                Ejj, jj = unit_indexed_tensor(wshape, wcomp)
            else:
                Ejj, jj = 1, ()
            gprimeterm = as_tensor(Ejj*Dvkk, jj+kk)
            return gprimeterm

        # Accumulate contributions from variations in different
        # components
        for (w, v) in zip(self._w, self._v):

            # Analyse differentiation variable coefficient
            if isinstance(w, FormArgument):
                if not w == o:
                    continue
                wshape = w.ufl_shape

                if isinstance(v, FormArgument):
                    # Case: d/dt [w + t v]
                    return apply_grads(v)

                elif isinstance(v, ListTensor):
                    # Case: d/dt [w + t <...,v,...>]
                    for wcomp, vsub in unwrap_list_tensor(v):
                        if not isinstance(vsub, Zero):
                            vval, vcomp = analyse_variation_argument(vsub)
                            gprimesum = gprimesum + compute_gprimeterm(ngrads, vval, vcomp, wshape, wcomp)

                else:
                    if wshape != ():
                        error("Expecting scalar coefficient in this branch.")
                    # Case: d/dt [w + t v[...]]
                    wval, wcomp = w, ()

                    vval, vcomp = analyse_variation_argument(v)
                    gprimesum = gprimesum + compute_gprimeterm(ngrads, vval,
                                                               vcomp, wshape,
                                                               wcomp)

            elif isinstance(w, Indexed):  # This path is tested in unit tests, but not actually used?
                # Case: d/dt [w[...] + t v[...]]
                # Case: d/dt [w[...] + t v]
                wval, wcomp = w.ufl_operands
                if not wval == o:
                    continue
                assert isinstance(wval, FormArgument)
                if not all(isinstance(k, FixedIndex) for k in wcomp):
                    error("Expecting only fixed indices in differentiation variable.")
                wshape = wval.ufl_shape

                vval, vcomp = analyse_variation_argument(v)
                gprimesum = gprimesum + compute_gprimeterm(ngrads, vval, vcomp, wshape, wcomp)

            else:
                error("Expecting coefficient or component of coefficient.")

        # FIXME: Handle other coefficient derivatives: oprimes =
        # self._cd.get(o)

        if 0:
            oprimes = self._cd.get(o)
            if oprimes is None:
                if self._cd:
                    # TODO: Make it possible to silence this message
                    #       in particular?  It may be good to have for
                    #       debugging...
                    warning("Assuming d{%s}/d{%s} = 0." % (o, self._w))
            else:
                # Make sure we have a tuple to match the self._v tuple
                if not isinstance(oprimes, tuple):
                    oprimes = (oprimes,)
                    if len(oprimes) != len(self._v):
                        error("Got a tuple of arguments, expecting a"
                              " matching tuple of coefficient derivatives.")

                # Compute dg/dw_j = dg/dw_h : v.
                # Since we may actually have a tuple of oprimes and vs
                # in a 'mixed' space, sum over them all to get the
                # complete inner product. Using indices to define a
                # non-compound inner product.
                for (oprime, v) in zip(oprimes, self._v):
                    error("FIXME: Figure out how to do this with ngrads")
                    so, oi = as_scalar(oprime)
                    rv = len(v.ufl_shape)
                    oi1 = oi[:-rv]
                    oi2 = oi[-rv:]
                    prod = so*v[oi2]
                    if oi1:
                        gprimesum += as_tensor(prod, oi1)
                    else:
                        gprimesum += prod

        return gprimesum
Exemple #27
0
 def expr(self, x):
     """The default is a nonlinear operator not accepting any
     Arguments among its children."""
     if _expr_has_terminal_types(x, Argument):
         error("Found Argument in %s, this is an invalid expression." % ufl_err_str(x))
     return (x, set())
Exemple #28
0
 def __getitem__(self, key):
     error(
         "Attempting to index with %s, but object is already indexed: %s" %
         (ufl_err_str(key), ufl_err_str(self)))
Exemple #29
0
def validate_form(
    form
):  # TODO: Can we make this return a list of errors instead of raising exception?
    """Performs all implemented validations on a form. Raises exception if something fails."""
    errors = []

    if not isinstance(form, Form):
        msg = "Validation failed, not a Form:\n%s" % ufl_err_str(form)
        error(msg)
        # errors.append(msg)
        # return errors

    # FIXME: There's a bunch of other checks we should do here.

    # FIXME: Add back check for multilinearity
    # Check that form is multilinear
    # if not is_multilinear(form):
    #     errors.append("Form is not multilinear in arguments.")

    # FIXME DOMAIN: Add check for consistency between domains somehow
    domains = set(t.ufl_domain() for e in iter_expressions(form)
                  for t in traverse_unique_terminals(e)) - {None}
    if not domains:
        errors.append("Missing domain definition in form.")

    # Check that cell is the same everywhere
    cells = set(dom.ufl_cell() for dom in domains) - {None}
    if not cells:
        errors.append("Missing cell definition in form.")
    elif len(cells) > 1:
        errors.append("Multiple cell definitions in form: %s" % str(cells))

    # Check that no Coefficient or Argument instance have the same
    # count unless they are the same
    coefficients = {}
    arguments = {}
    for e in iter_expressions(form):
        for f in traverse_unique_terminals(e):
            if isinstance(f, Coefficient):
                c = f.count()
                if c in coefficients:
                    g = coefficients[c]
                    if f is not g:
                        errors.append("Found different Coefficients with " +
                                      "same count: %s and %s." %
                                      (repr(f), repr(g)))
                else:
                    coefficients[c] = f

            elif isinstance(f, Argument):
                n = f.number()
                p = f.part()
                if (n, p) in arguments:
                    g = arguments[(n, p)]
                    if f is not g:
                        if n == 0:
                            msg = "TestFunctions"
                        elif n == 1:
                            msg = "TrialFunctions"
                        else:
                            msg = "Arguments with same number and part"
                        msg = "Found different %s: %s and %s." % (msg, repr(f),
                                                                  repr(g))
                        errors.append(msg)
                else:
                    arguments[(n, p)] = f

    # Check that all integrands are scalar
    for expression in iter_expressions(form):
        if not is_true_ufl_scalar(expression):
            errors.append("Found non-scalar integrand expression: %s\n" %
                          ufl_err_str(expression))

    # Check that restrictions are permissible
    for integral in form.integrals():
        # Only allow restrictions on interior facet integrals and
        # surface measures
        if integral.integral_type().startswith("interior_facet"):
            check_restrictions(integral.integrand(), True)
        else:
            check_restrictions(integral.integrand(), False)

    # Raise exception with all error messages
    # TODO: Return errors list instead, need to collect messages from
    # all validations above first.
    if errors:
        final_msg = 'Found errors in validation of form:\n%s' % '\n\n'.join(
            errors)
        error(final_msg)
Exemple #30
0
def expecting_true_ufl_scalar(v):
    error("Expecting UFL scalar expression with no free indices, not %s." % ufl_err_str(v))
Exemple #31
0
def expecting_terminal(v):
    error("Expecting Terminal instance, not %s." % ufl_err_str(v))
Exemple #32
0
def validate_form(form):  # TODO: Can we make this return a list of errors instead of raising exception?
    """Performs all implemented validations on a form. Raises exception if something fails."""
    errors = []

    if not isinstance(form, Form):
        msg = "Validation failed, not a Form:\n%s" % ufl_err_str(form)
        error(msg)
        # errors.append(msg)
        # return errors

    # FIXME: There's a bunch of other checks we should do here.

    # FIXME: Add back check for multilinearity
    # Check that form is multilinear
    # if not is_multilinear(form):
    #     errors.append("Form is not multilinear in arguments.")

    # FIXME DOMAIN: Add check for consistency between domains somehow
    domains = set(t.ufl_domain()
                  for e in iter_expressions(form)
                  for t in traverse_unique_terminals(e)) - {None}
    if not domains:
        errors.append("Missing domain definition in form.")

    # Check that cell is the same everywhere
    cells = set(dom.ufl_cell() for dom in domains) - {None}
    if not cells:
        errors.append("Missing cell definition in form.")
    elif len(cells) > 1:
        errors.append("Multiple cell definitions in form: %s" % str(cells))

    # Check that no Coefficient or Argument instance have the same
    # count unless they are the same
    coefficients = {}
    arguments = {}
    for e in iter_expressions(form):
        for f in traverse_unique_terminals(e):
            if isinstance(f, Coefficient):
                c = f.count()
                if c in coefficients:
                    g = coefficients[c]
                    if f is not g:
                        errors.append("Found different Coefficients with " +
                                      "same count: %s and %s." % (repr(f),
                                                                  repr(g)))
                else:
                    coefficients[c] = f

            elif isinstance(f, Argument):
                n = f.number()
                p = f.part()
                if (n, p) in arguments:
                    g = arguments[(n, p)]
                    if f is not g:
                        if n == 0:
                            msg = "TestFunctions"
                        elif n == 1:
                            msg = "TrialFunctions"
                        else:
                            msg = "Arguments with same number and part"
                        msg = "Found different %s: %s and %s." % (msg, repr(f), repr(g))
                        errors.append(msg)
                else:
                    arguments[(n, p)] = f

    # Check that all integrands are scalar
    for expression in iter_expressions(form):
        if not is_true_ufl_scalar(expression):
            errors.append("Found non-scalar integrand expression: %s\n" %
                          ufl_err_str(expression))

    # Check that restrictions are permissible
    for integral in form.integrals():
        # Only allow restrictions on interior facet integrals and
        # surface measures
        if integral.integral_type().startswith("interior_facet"):
            check_restrictions(integral.integrand(), True)
        else:
            check_restrictions(integral.integrand(), False)

    # Raise exception with all error messages
    # TODO: Return errors list instead, need to collect messages from
    # all validations above first.
    if errors:
        final_msg = 'Found errors in validation of form:\n%s' % '\n\n'.join(errors)
        error(final_msg)
Exemple #33
0
 def __init__(self, a):
     Operator.__init__(self, (a, ))
     if not isinstance(a, Expr):
         error("Expecting Expr instance, not %s." % ufl_err_str(a))
Exemple #34
0
def as_form(form):
    "Convert to form if not a form, otherwise return form."
    if not isinstance(form, Form):
        error("Unable to convert object to a UFL form: %s" % ufl_err_str(form))
    return form
Exemple #35
0
def as_form(form):
    "Convert to form if not a form, otherwise return form."
    if not isinstance(form, Form):
        error("Unable to convert object to a UFL form: %s" % ufl_err_str(form))
    return form
Exemple #36
0
def sub_forms_by_domain(form):
    "Return a list of forms each with an integration domain"
    if not isinstance(form, Form):
        error("Unable to convert object to a UFL form: %s" % ufl_err_str(form))
    return [Form(form.integrals_by_domain(domain)) for domain in form.ufl_domains()]
Exemple #37
0
def _handle_derivative_arguments(form, coefficient, argument):
    # Wrap single coefficient in tuple for uniform treatment below
    if isinstance(coefficient, (list, tuple, ListTensor)):
        coefficients = tuple(coefficient)
    else:
        coefficients = (coefficient,)

    if argument is None:
        # Try to create argument if not provided
        if not all(isinstance(c, Coefficient) for c in coefficients):
            error("Can only create arguments automatically for non-indexed coefficients.")

        # Get existing arguments from form and position the new one
        # with the next argument number
        if isinstance(form, Form):
            form_arguments = form.arguments()
        else:
            # To handle derivative(expression), which is at least used
            # in tests. Remove?
            form_arguments = extract_arguments(form)

        numbers = sorted(set(arg.number() for arg in form_arguments))
        number = max(numbers + [-1]) + 1

        # Don't know what to do with parts, let the user sort it out
        # in that case
        parts = set(arg.part() for arg in form_arguments)
        if len(parts - {None}) != 0:
            error("Not expecting parts here, provide your own arguments.")
        part = None

        # Create argument and split it if in a mixed space
        function_spaces = [c.ufl_function_space() for c in coefficients]
        domains = [fs.ufl_domain() for fs in function_spaces]
        elements = [fs.ufl_element() for fs in function_spaces]
        if len(function_spaces) == 1:
            arguments = (Argument(function_spaces[0], number, part),)
        else:
            # Create in mixed space over assumed (for now) same domain
            assert all(fs.ufl_domain() == domains[0] for fs in function_spaces)
            elm = MixedElement(*elements)
            fs = FunctionSpace(domains[0], elm)
            arguments = split(Argument(fs, number, part))
    else:
        # Wrap single argument in tuple for uniform treatment below
        if isinstance(argument, (list, tuple)):
            arguments = tuple(argument)
        else:
            n = len(coefficients)
            if n == 1:
                arguments = (argument,)
            else:
                if argument.ufl_shape == (n,):
                    arguments = tuple(argument[i] for i in range(n))
                else:
                    arguments = split(argument)

    # Build mapping from coefficient to argument
    m = {}
    for (c, a) in zip(coefficients, arguments):
        if c.ufl_shape != a.ufl_shape:
            error("Coefficient and argument shapes do not match!")
        if isinstance(c, Coefficient) or isinstance(c, SpatialCoordinate):
            m[c] = a
        else:
            if not isinstance(c, Indexed):
                error("Invalid coefficient type for %s" % ufl_err_str(c))
            f, i = c.ufl_operands
            if not isinstance(f, Coefficient):
                error("Expecting an indexed coefficient, not %s" % ufl_err_str(f))
            if not (isinstance(i, MultiIndex) and all(isinstance(j, FixedIndex) for j in i)):
                error("Expecting one or more fixed indices, not %s" % ufl_err_str(i))
            i = tuple(int(j) for j in i)
            if f not in m:
                m[f] = {}
            m[f][i] = a

    # Merge coefficient derivatives (arguments) based on indices
    for c, p in m.items():
        if isinstance(p, dict):
            a = zero_lists(c.ufl_shape)
            for i, g in p.items():
                set_list_item(a, i, g)
            m[c] = as_tensor(a)

    # Wrap and return generic tuples
    items = sorted(m.items(), key=lambda x: x[0].count())
    coefficients = ExprList(*[item[0] for item in items])
    arguments = ExprList(*[item[1] for item in items])
    return coefficients, arguments
Exemple #38
0
def expecting_instance(v, c):
    error("Expecting %s instance, not %s." % (c.__name__, ufl_err_str(v)))
Exemple #39
0
def expecting_instance(v, c):
    error("Expecting %s instance, not %s." % (c.__name__, ufl_err_str(v)))
Exemple #40
0
    def division(self, x):
        "Return parts_of_numerator/denominator."

        # Get numerator and denominator
        numerator, denominator = x.ufl_operands

        # Check for Arguments in the denominator
        if _expr_has_terminal_types(denominator, Argument):
            error("Found Argument in denominator of %s , this is an invalid expression." % ufl_err_str(x))

        # Visit numerator
        numerator_parts, provides = self.visit(numerator)

        # If numerator is zero, return zero. (No need to check whether
        # it provides too much, already checked by visit.)
        if isinstance(numerator_parts, Zero):
            return (zero_expr(x), set())

        # Reuse x if possible, otherwise reconstruct from (parts of)
        # numerator and denominator
        x = self.reuse_if_possible(x, numerator_parts, denominator)

        return (x, provides)
Exemple #41
0
def expecting_python_scalar(v):
    error("Expecting Python scalar, not %s." % ufl_err_str(v))
Exemple #42
0
def expecting_expr(v):
    error("Expecting Expr instance, not %s." % ufl_err_str(v))
Exemple #43
0
    def grad(self, g):
        # If we hit this type, it has already been propagated to a
        # coefficient (or grad of a coefficient), # FIXME: Assert
        # this!  so we need to take the gradient of the variation or
        # return zero.  Complications occur when dealing with
        # derivatives w.r.t. single components...

        # Figure out how many gradients are around the inner terminal
        ngrads = 0
        o = g
        while isinstance(o, Grad):
            o, = o.ufl_operands
            ngrads += 1
        if not isinstance(o, FormArgument):
            error("Expecting gradient of a FormArgument, not %s" %
                  ufl_err_str(o))

        def apply_grads(f):
            for i in range(ngrads):
                f = Grad(f)
            return f

        # Find o among all w without any indexing, which makes this
        # easy
        for (w, v) in zip(self._w, self._v):
            if o == w and isinstance(v, FormArgument):
                # Case: d/dt [w + t v]
                return apply_grads(v)

        # If o is not among coefficient derivatives, return do/dw=0
        gprimesum = Zero(g.ufl_shape)

        def analyse_variation_argument(v):
            # Analyse variation argument
            if isinstance(v, FormArgument):
                # Case: d/dt [w[...] + t v]
                vval, vcomp = v, ()
            elif isinstance(v, Indexed):
                # Case: d/dt [w + t v[...]]
                # Case: d/dt [w[...] + t v[...]]
                vval, vcomp = v.ufl_operands
                vcomp = tuple(vcomp)
            else:
                error("Expecting argument or component of argument.")
            if not all(isinstance(k, FixedIndex) for k in vcomp):
                error("Expecting only fixed indices in variation.")
            return vval, vcomp

        def compute_gprimeterm(ngrads, vval, vcomp, wshape, wcomp):
            # Apply gradients directly to argument vval, and get the
            # right indexed scalar component(s)
            kk = indices(ngrads)
            Dvkk = apply_grads(vval)[vcomp + kk]
            # Place scalar component(s) Dvkk into the right tensor
            # positions
            if wshape:
                Ejj, jj = unit_indexed_tensor(wshape, wcomp)
            else:
                Ejj, jj = 1, ()
            gprimeterm = as_tensor(Ejj * Dvkk, jj + kk)
            return gprimeterm

        # Accumulate contributions from variations in different
        # components
        for (w, v) in zip(self._w, self._v):

            # Analyse differentiation variable coefficient
            if isinstance(w, FormArgument):
                if not w == o:
                    continue
                wshape = w.ufl_shape

                if isinstance(v, FormArgument):
                    # Case: d/dt [w + t v]
                    return apply_grads(v)

                elif isinstance(v, ListTensor):
                    # Case: d/dt [w + t <...,v,...>]
                    for wcomp, vsub in unwrap_list_tensor(v):
                        if not isinstance(vsub, Zero):
                            vval, vcomp = analyse_variation_argument(vsub)
                            gprimesum = gprimesum + compute_gprimeterm(
                                ngrads, vval, vcomp, wshape, wcomp)

                else:
                    if wshape != ():
                        error("Expecting scalar coefficient in this branch.")
                    # Case: d/dt [w + t v[...]]
                    wval, wcomp = w, ()

                    vval, vcomp = analyse_variation_argument(v)
                    gprimesum = gprimesum + compute_gprimeterm(
                        ngrads, vval, vcomp, wshape, wcomp)

            elif isinstance(
                    w, Indexed
            ):  # This path is tested in unit tests, but not actually used?
                # Case: d/dt [w[...] + t v[...]]
                # Case: d/dt [w[...] + t v]
                wval, wcomp = w.ufl_operands
                if not wval == o:
                    continue
                assert isinstance(wval, FormArgument)
                if not all(isinstance(k, FixedIndex) for k in wcomp):
                    error(
                        "Expecting only fixed indices in differentiation variable."
                    )
                wshape = wval.ufl_shape

                vval, vcomp = analyse_variation_argument(v)
                gprimesum = gprimesum + compute_gprimeterm(
                    ngrads, vval, vcomp, wshape, wcomp)

            else:
                error("Expecting coefficient or component of coefficient.")

        # FIXME: Handle other coefficient derivatives: oprimes =
        # self._cd.get(o)

        if 0:
            oprimes = self._cd.get(o)
            if oprimes is None:
                if self._cd:
                    # TODO: Make it possible to silence this message
                    #       in particular?  It may be good to have for
                    #       debugging...
                    warning("Assuming d{%s}/d{%s} = 0." % (o, self._w))
            else:
                # Make sure we have a tuple to match the self._v tuple
                if not isinstance(oprimes, tuple):
                    oprimes = (oprimes, )
                    if len(oprimes) != len(self._v):
                        error("Got a tuple of arguments, expecting a"
                              " matching tuple of coefficient derivatives.")

                # Compute dg/dw_j = dg/dw_h : v.
                # Since we may actually have a tuple of oprimes and vs
                # in a 'mixed' space, sum over them all to get the
                # complete inner product. Using indices to define a
                # non-compound inner product.
                for (oprime, v) in zip(oprimes, self._v):
                    error("FIXME: Figure out how to do this with ngrads")
                    so, oi = as_scalar(oprime)
                    rv = len(v.ufl_shape)
                    oi1 = oi[:-rv]
                    oi2 = oi[-rv:]
                    prod = so * v[oi2]
                    if oi1:
                        gprimesum += as_tensor(prod, oi1)
                    else:
                        gprimesum += prod

        return gprimesum
Exemple #44
0
 def __getitem__(self, key):
     error("Attempting to index with %s, but object is already indexed: %s" % (ufl_err_str(key), ufl_err_str(self)))