Exemple #1
0
class Operator(Expr):
    "Base class for all operators, i.e. non-terminal expression types."
    __slots__ = as_native_strings(("ufl_operands", ))

    def __init__(self, operands=None):
        Expr.__init__(self)

        # If operands is None, the type sets this itself. This is to
        # get around some tricky too-fancy __new__/__init__ design in
        # algebra.py, for now.  It would be nicer to make the classes
        # in algebra.py pass operands here.
        if operands is not None:
            self.ufl_operands = operands

    def _ufl_expr_reconstruct_(self, *operands):
        "Return a new object of the same type with new operands."
        return self._ufl_class_(*operands)

    def _ufl_signature_data_(self):
        return self._ufl_typecode_

    def _ufl_compute_hash_(self):
        "Compute a hash code for this expression. Used by sets and dicts."
        return hash((self._ufl_typecode_, ) +
                    tuple(hash(o) for o in self.ufl_operands))

    def __repr__(self):
        "Default repr string construction for operators."
        # This should work for most cases
        r = "%s(%s)" % (self._ufl_class_.__name__, ", ".join(
            repr(op) for op in self.ufl_operands))
        return as_native_str(r)
Exemple #2
0
class BinaryCondition(Condition):
    __slots__ = as_native_strings(('_name',))

    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.")

    def __str__(self):
        return "%s %s %s" % (parstr(self.ufl_operands[0], self),
                             self._name, parstr(self.ufl_operands[1], self))
Exemple #3
0
class Cross(CompoundTensorOperator):
    __slots__ = as_native_strings(("ufl_free_indices",
                                   "ufl_index_dimensions"))

    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)

    def __init__(self, a, b):
        CompoundTensorOperator.__init__(self, (a, b))
        fi, fid = merge_nonoverlapping_indices(a, b)
        self.ufl_free_indices = fi
        self.ufl_index_dimensions = fid

    ufl_shape = (3,)

    def __str__(self):
        return "%s x %s" % (parstr(self.ufl_operands[0], self),
                            parstr(self.ufl_operands[1], self))
Exemple #4
0
class NablaGrad(CompoundDerivative):
    __slots__ = as_native_strings(("_dim",))

    def __new__(cls, f):
        # Return zero if expression is trivially constant
        if is_cellwise_constant(f):
            dim = find_geometric_dimension(f)
            return Zero((dim,) + f.ufl_shape, f.ufl_free_indices,
                        f.ufl_index_dimensions)
        return CompoundDerivative.__new__(cls)

    def __init__(self, f):
        CompoundDerivative.__init__(self, (f,))
        self._dim = find_geometric_dimension(f)

    def _ufl_expr_reconstruct_(self, op):
        "Return a new object of the same type with new operands."
        if is_cellwise_constant(op):
            if op.ufl_shape != self.ufl_operands[0].ufl_shape:
                error("Operand shape mismatch in NablaGrad reconstruct.")
            if self.ufl_operands[0].ufl_free_indices != op.ufl_free_indices:
                error("Free index mismatch in NablaGrad reconstruct.")
            return Zero(self.ufl_shape, self.ufl_free_indices,
                        self.ufl_index_dimensions)
        return self._ufl_class_(op)

    @property
    def ufl_shape(self):
        return (self._dim,) + self.ufl_operands[0].ufl_shape

    def __str__(self):
        return "nabla_grad(%s)" % self.ufl_operands[0]
Exemple #5
0
class MathFunction(Operator):
    "Base class for all unary scalar math functions."
    # Freeze member variables for objects in this class
    __slots__ = as_native_strings(("_name", ))

    def __init__(self, name, argument):
        Operator.__init__(self, (argument, ))
        if not is_true_ufl_scalar(argument):
            error("Expecting scalar argument.")
        self._name = name

    def evaluate(self, x, mapping, component, index_values):
        a = self.ufl_operands[0].evaluate(x, mapping, component, index_values)
        try:
            if isinstance(a, numbers.Real):
                res = getattr(math, self._name)(a)
            else:
                res = getattr(cmath, self._name)(a)
        except ValueError:
            warning(
                'Value error in evaluation of function %s with argument %s.' %
                (self._name, a))
            raise
        return res

    def __str__(self):
        return "%s(%s)" % (self._name, self.ufl_operands[0])
Exemple #6
0
class MeasureSum(object):
    """Represents a sum of measures.

    This is a notational intermediate object to translate the notation

        f*(ds(1)+ds(3))

    into

        f*ds(1) + f*ds(3)
    """
    __slots__ = as_native_strings(("_measures",))

    def __init__(self, *measures):
        self._measures = measures

    def __rmul__(self, other):
        integrals = [other*m for m in self._measures]
        return sum(integrals)

    def __add__(self, other):
        if isinstance(other, Measure):
            return MeasureSum(*(self._measures + (other,)))
        elif isinstance(other, MeasureSum):
            return MeasureSum(*(self._measures + other._measures))
        return NotImplemented

    def __str__(self):
        return "{\n    " + "\n  + ".join(map(str, self._measures)) + "\n}"
Exemple #7
0
class Outer(CompoundTensorOperator):
    __slots__ = as_native_strings(("ufl_free_indices",
                                   "ufl_index_dimensions"))

    def __new__(cls, a, b):
        ash, bsh = a.ufl_shape, b.ufl_shape
        if isinstance(a, Zero) or isinstance(b, Zero):
            fi, fid = merge_nonoverlapping_indices(a, b)
            return Zero(ash + bsh, fi, fid)
        if ash == () or bsh == ():
            return a * b
        return CompoundTensorOperator.__new__(cls)

    def __init__(self, a, b):
        CompoundTensorOperator.__init__(self, (a, b))
        fi, fid = merge_nonoverlapping_indices(a, b)
        self.ufl_free_indices = fi
        self.ufl_index_dimensions = fid

    @property
    def ufl_shape(self):
        return self.ufl_operands[0].ufl_shape + self.ufl_operands[1].ufl_shape

    def __str__(self):
        return "%s (X) %s" % (parstr(self.ufl_operands[0], self),
                              parstr(self.ufl_operands[1], self))
Exemple #8
0
class Index(IndexBase):
    """UFL value: An index with no value assigned.

    Used to represent free indices in Einstein indexing notation."""
    __slots__ = as_native_strings(("_count", ))

    _globalcount = 0

    def __init__(self, count=None):
        IndexBase.__init__(self)
        counted_init(self, count, Index)

    def count(self):
        return self._count

    def __hash__(self):
        return hash(("Index", self._count))

    def __eq__(self, other):
        return isinstance(other, Index) and (self._count == other._count)

    def __str__(self):
        c = str(self._count)
        if len(c) > 1:
            c = "{%s}" % c
        return "i_%s" % c

    def __repr__(self):
        r = "Index(%d)" % self._count
        return as_native_str(r)
Exemple #9
0
class Inner(CompoundTensorOperator):
    __slots__ = as_native_strings(("ufl_free_indices",
                                   "ufl_index_dimensions"))

    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)

    def __init__(self, a, b):
        # sort operands for unique representation, must be independent
        # of various counts etc.  as explained in cmp_expr
        a, b = sorted_expr((a, b))

        CompoundTensorOperator.__init__(self, (a, b))

        fi, fid = merge_nonoverlapping_indices(a, b)
        self.ufl_free_indices = fi
        self.ufl_index_dimensions = fid

    ufl_shape = ()

    def __str__(self):
        return "%s : %s" % (parstr(self.ufl_operands[0], self),
                            parstr(self.ufl_operands[1], self))
Exemple #10
0
class Identity(ConstantValue):
    "UFL literal type: Representation of an identity matrix."
    __slots__ = as_native_strings(("_dim", "ufl_shape"))

    def __init__(self, dim):
        ConstantValue.__init__(self)
        self._dim = dim
        self.ufl_shape = (dim, dim)

    def evaluate(self, x, mapping, component, index_values):
        "Evaluates the identity matrix on the given components."
        a, b = component
        return 1 if a == b else 0

    def __getitem__(self, key):
        if len(key) != 2:
            error("Size mismatch for Identity.")
        if all(isinstance(k, (int, FixedIndex)) for k in key):
            return IntValue(1) if (int(key[0]) == int(key[1])) else Zero()
        return Expr.__getitem__(self, key)

    def __str__(self):
        return "I"

    def __repr__(self):
        r = "Identity(%d)" % self._dim
        return as_native_str(r)

    def __eq__(self, other):
        return isinstance(other, Identity) and self._dim == other._dim
Exemple #11
0
class ScalarValue(ConstantValue):
    "A constant scalar value."
    __slots__ = as_native_strings(("_value",))

    def __init__(self, value):
        ConstantValue.__init__(self)
        self._value = value

    def value(self):
        return self._value

    def evaluate(self, x, mapping, component, index_values):
        return self._value

    def __eq__(self, other):
        """This is implemented to allow comparison with python scalars.

        Note that this will make IntValue(1) != FloatValue(1.0),
        but ufl-python comparisons like
            IntValue(1) == 1.0
            FloatValue(1.0) == 1
        can still succeed. These will however not have the same
        hash value and therefore not collide in a dict.
        """
        if isinstance(other, self._ufl_class_):
            return self._value == other._value
        elif isinstance(other, (int, float)):
            # FIXME: Disallow this, require explicit 'expr ==
            # IntValue(3)' instead to avoid ambiguities!
            return other == self._value
        else:
            return False

    def __str__(self):
        return str(self._value)

    def __float__(self):
        return float(self._value)

    def __int__(self):
        return int(self._value)

    def __complex__(self):
        return complex(self._value)

    def __neg__(self):
        return type(self)(-self._value)

    def __abs__(self):
        return type(self)(abs(self._value))

    def real(self):
        return self._value.real

    def imag(self):
        return self._value.imag
Exemple #12
0
class IntegralData(object):
    """Utility class with the members (domain, integral_type,
        subdomain_id, integrals, metadata)

    where metadata is an empty dictionary that may be used for
    associating metadata with each object.

    """
    __slots__ = as_native_strings(
        ('domain', 'integral_type', 'subdomain_id', 'integrals', 'metadata',
         'integral_coefficients', 'enabled_coefficients'))

    def __init__(self, domain, integral_type, subdomain_id, integrals,
                 metadata):
        if 1 != len(set(itg.ufl_domain() for itg in integrals)):
            error("Multiple domains mismatch in integral data.")
        if not all(integral_type == itg.integral_type() for itg in integrals):
            error("Integral type mismatch in integral data.")
        if not all(subdomain_id == itg.subdomain_id() for itg in integrals):
            error("Subdomain id mismatch in integral data.")

        self.domain = domain
        self.integral_type = integral_type
        self.subdomain_id = subdomain_id

        self.integrals = integrals

        # This is populated in preprocess using data not available at
        # this stage:
        self.integral_coefficients = None
        self.enabled_coefficients = None

        # TODO: I think we can get rid of this with some refactoring
        # in ffc:
        self.metadata = metadata

    def __lt__(self, other):
        # To preserve behaviour of extract_integral_data:
        return ((self.integral_type, self.subdomain_id, self.integrals,
                 self.metadata) < (other.integral_type, other.subdomain_id,
                                   other.integrals, other.metadata))

    def __eq__(self, other):
        # Currently only used for tests:
        return (self.integral_type == other.integral_type
                and self.subdomain_id == other.subdomain_id
                and self.integrals == other.integrals
                and self.metadata == other.metadata)

    def __str__(self):
        s = "IntegralData over domain(%s, %s), with integrals:\n%s\nand metadata:\n%s" % (
            self.integral_type, self.subdomain_id, '\n\n'.join(
                map(str, self.integrals)), self.metadata)
        return s
Exemple #13
0
class AbstractCell(object):
    """Representation of an abstract finite element cell with only the
    dimensions known.

    """
    __slots__ = as_native_strings(
        ("_topological_dimension", "_geometric_dimension"))

    def __init__(self, topological_dimension, geometric_dimension):
        # Validate dimensions
        if not isinstance(geometric_dimension, numbers.Integral):
            error("Expecting integer geometric_dimension.")
        if not isinstance(topological_dimension, numbers.Integral):
            error("Expecting integer topological_dimension.")
        if topological_dimension > geometric_dimension:
            error(
                "Topological dimension cannot be larger than geometric dimension."
            )

        # Store validated dimensions
        self._topological_dimension = topological_dimension
        self._geometric_dimension = geometric_dimension

    def topological_dimension(self):
        "Return the dimension of the topology of this cell."
        return self._topological_dimension

    def geometric_dimension(self):
        "Return the dimension of the space this cell is embedded in."
        return self._geometric_dimension

    def is_simplex(self):
        "Return True if this is a simplex cell."
        raise NotImplementedError(
            "Implement this to allow important checks and optimizations.")

    def has_simplex_facets(self):
        "Return True if all the facets of this cell are simplex cells."
        raise NotImplementedError(
            "Implement this to allow important checks and optimizations.")

    def __lt__(self, other):
        "Define an arbitrarily chosen but fixed sort order for all cells."
        if not isinstance(other, AbstractCell):
            return NotImplemented
        # Sort by gdim first, tdim next, then whatever's left
        # depending on the subclass
        s = (self.geometric_dimension(), self.topological_dimension())
        o = (other.geometric_dimension(), other.topological_dimension())
        if s != o:
            return s < o
        return self._ufl_hash_data_() < other._ufl_hash_data_()
Exemple #14
0
class PermutationSymbol(ConstantValue):
    """UFL literal type: Representation of a permutation symbol.

    This is also known as the Levi-Civita symbol, antisymmetric symbol,
    or alternating symbol."""
    __slots__ = as_native_strings(("ufl_shape", "_dim"))

    def __init__(self, dim):
        ConstantValue.__init__(self)
        self._dim = dim
        self.ufl_shape = (dim,)*dim

    def evaluate(self, x, mapping, component, index_values):
        "Evaluates the permutation symbol."
        return self.__eps(component)

    def __getitem__(self, key):
        if len(key) != self._dim:
            error("Size mismatch for PermutationSymbol.")
        if all(isinstance(k, (int, FixedIndex)) for k in key):
            return self.__eps(key)
        return Expr.__getitem__(self, key)

    def __str__(self):
        return "eps"

    def __repr__(self):
        r = "PermutationSymbol(%d)" % self._dim
        return as_native_str(r)

    def __eq__(self, other):
        return isinstance(other, PermutationSymbol) and self._dim == other._dim

    def __eps(self, x):
        """This function body is taken from
        http://www.mathkb.com/Uwe/Forum.aspx/math/29865/N-integer-Levi-Civita

        """
        result = IntValue(1)
        for i, x1 in enumerate(x):
            for j in range(i + 1, len(x)):
                x2 = x[j]
                if x1 > x2:
                    result = -result
                elif x1 == x2:
                    return Zero()
        return result
Exemple #15
0
class BesselFunction(Operator):
    "Base class for all bessel functions"
    __slots__ = as_native_strings(("_name", "_classname"))

    def __init__(self, name, classname, nu, argument):
        if not is_true_ufl_scalar(nu):
            error("Expecting scalar nu.")
        if not is_true_ufl_scalar(argument):
            error("Expecting scalar argument.")

        # Use integer representation if suitable
        fnu = float(nu)
        inu = int(nu)
        if fnu == inu:
            nu = as_ufl(inu)
        else:
            nu = as_ufl(fnu)

        Operator.__init__(self, (nu, argument))

        self._classname = classname
        self._name = name

    def evaluate(self, x, mapping, component, index_values):
        a = self.ufl_operands[1].evaluate(x, mapping, component, index_values)
        try:
            import scipy.special
        except ImportError:
            error(
                "You must have scipy installed to evaluate bessel functions in python."
            )
        name = self._name[-1]
        if isinstance(self.ufl_operands[0], IntValue):
            nu = int(self.ufl_operands[0])
            functype = 'n' if name != 'i' else 'v'
        else:
            nu = self.ufl_operands[0].evaluate(x, mapping, component,
                                               index_values)
            functype = 'v'
        func = getattr(scipy.special, name + functype)
        return func(nu, a)

    def __str__(self):
        return "%s(%s, %s)" % (self._name, self.ufl_operands[0],
                               self.ufl_operands[1])
Exemple #16
0
class ExampleCounted(object):
    """An example class for classes of objects identified by a global counter.

    Mimic this class to create globally counted objects within a single type.
    """
    # Store the count for each object
    __slots__ = as_native_strings(("_count", ))

    # Store a global counter with the class
    _globalcount = 0

    # Call counted_init with an optional constructor argument and the class
    def __init__(self, count=None):
        counted_init(self, count, ExampleCounted)

    # Make the count accessible
    def count(self):
        return self._count
Exemple #17
0
class ExprTupleKey(object):
    __slots__ = as_native_strings(('x', ))

    def __init__(self, x):
        self.x = x

    def __lt__(self, other):
        # Comparing expression first
        c = cmp_expr(self.x[0], other.x[0])
        if c < 0:
            return True
        elif c > 0:
            return False
        else:
            # Comparing form compiler data
            mds = canonicalize_metadata(self.x[1])
            mdo = canonicalize_metadata(other.x[1])
            return mds < mdo
class ReferenceGrad(CompoundDerivative):
    __slots__ = as_native_strings(("_dim", ))

    def __new__(cls, f):
        # Return zero if expression is trivially constant
        if is_cellwise_constant(f):
            dim = f.ufl_domain().topological_dimension()
            return Zero(f.ufl_shape + (dim, ), f.ufl_free_indices,
                        f.ufl_index_dimensions)
        return CompoundDerivative.__new__(cls)

    def __init__(self, f):
        CompoundDerivative.__init__(self, (f, ))
        self._dim = f.ufl_domain().topological_dimension()

    def _ufl_expr_reconstruct_(self, op):
        "Return a new object of the same type with new operands."
        if is_cellwise_constant(op):
            if op.ufl_shape != self.ufl_operands[0].ufl_shape:
                error("Operand shape mismatch in ReferenceGrad reconstruct.")
            if self.ufl_operands[0].ufl_free_indices != op.ufl_free_indices:
                error("Free index mismatch in ReferenceGrad reconstruct.")
            return Zero(self.ufl_shape, self.ufl_free_indices,
                        self.ufl_index_dimensions)
        return self._ufl_class_(op)

    def evaluate(self, x, mapping, component, index_values, derivatives=()):
        "Get child from mapping and return the component asked for."
        component, i = component[:-1], component[-1]
        derivatives = derivatives + (i, )
        result = self.ufl_operands[0].evaluate(x,
                                               mapping,
                                               component,
                                               index_values,
                                               derivatives=derivatives)
        return result

    @property
    def ufl_shape(self):
        return self.ufl_operands[0].ufl_shape + (self._dim, )

    def __str__(self):
        return "reference_grad(%s)" % self.ufl_operands[0]
Exemple #19
0
class FixedIndex(IndexBase):
    """UFL value: An index with a specific value assigned."""
    __slots__ = as_native_strings(("_value", "_hash"))

    _cache = {}

    def __getnewargs__(self):
        return (self._value, )

    def __new__(cls, value):
        self = FixedIndex._cache.get(value)
        if self is None:
            if not isinstance(value, int):
                error("Expecting integer value for fixed index.")
            self = IndexBase.__new__(cls)
            self._init(value)
            FixedIndex._cache[value] = self
        return self

    def _init(self, value):
        IndexBase.__init__(self)
        self._value = value
        self._hash = hash(("FixedIndex", self._value))

    def __init__(self, value):
        pass

    def __hash__(self):
        return self._hash

    def __eq__(self, other):
        return isinstance(other, FixedIndex) and (self._value == other._value)

    def __int__(self):
        return self._value

    def __str__(self):
        return "%d" % self._value

    def __repr__(self):
        r = "FixedIndex(%d)" % self._value
        return as_native_str(r)
Exemple #20
0
class Dot(CompoundTensorOperator):
    __slots__ = as_native_strings(("ufl_free_indices",
                                   "ufl_index_dimensions"))

    def __new__(cls, a, b):
        ash = a.ufl_shape
        bsh = b.ufl_shape
        ar, br = len(ash), len(bsh)
        scalar = (ar == 0 and br == 0)

        # Checks
        if not ((ar >= 1 and br >= 1) or scalar):
            error("Dot product requires non-scalar arguments, "
                  "got arguments with ranks %d and %d." % (ar, br))
        if not (scalar or ash[-1] == bsh[0]):
            error("Dimension mismatch in dot product.")

        # Simplification
        if isinstance(a, Zero) or isinstance(b, Zero):
            shape = ash[:-1] + bsh[1:]
            fi, fid = merge_nonoverlapping_indices(a, b)
            return Zero(shape, fi, fid)
        elif scalar:  # TODO: Move this to def dot()?
            return a * b

        return CompoundTensorOperator.__new__(cls)

    def __init__(self, a, b):
        CompoundTensorOperator.__init__(self, (a, b))
        fi, fid = merge_nonoverlapping_indices(a, b)
        self.ufl_free_indices = fi
        self.ufl_index_dimensions = fid

    @property
    def ufl_shape(self):
        return self.ufl_operands[0].ufl_shape[:-1] + self.ufl_operands[1].ufl_shape[1:]

    def __str__(self):
        return "%s . %s" % (parstr(self.ufl_operands[0], self),
                            parstr(self.ufl_operands[1], self))
Exemple #21
0
class MeasureProduct(object):
    """Represents a product of measures.

    This is a notational intermediate object to handle the notation

        f*(dm1*dm2)

    This is work in progress and not functional. It needs support
    in other parts of ufl and the rest of the code generation chain.

    """
    __slots__ = as_native_strings(("_measures", ))

    def __init__(self, *measures):
        "Create MeasureProduct from given list of measures."
        self._measures = measures
        if len(self._measures) < 2:
            error("Expecting at least two measures.")

    def __mul__(self, other):
        """Flatten multiplication of product measures.

        This is to ensure that (dm1*dm2)*dm3 is stored as a simple
        list (dm1,dm2,dm3) in a single MeasureProduct.

        """
        if isinstance(other, Measure):
            measures = self.sub_measures() + [other]
            return MeasureProduct(*measures)
        else:
            return NotImplemented

    def __rmul__(self, integrand):
        error(
            "TODO: Implement MeasureProduct.__rmul__ to construct integral and form somehow."
        )

    def sub_measures(self):
        "Return submeasures."
        return self._measures
Exemple #22
0
class HCurlElement(FiniteElementBase):
    """A curl-conforming version of an outer product element, assuming
    this makes mathematical sense."""
    __slots__ = as_native_strings(("_element", ))

    def __init__(self, element):
        self._element = element
        self._repr = as_native_str("HCurlElement(%s)" % repr(element))

        family = "TensorProductElement"
        cell = element.cell()
        degree = element.degree()
        quad_scheme = element.quadrature_scheme()
        cell = element.cell()
        value_shape = (cell.geometric_dimension(), )
        reference_value_shape = (cell.topological_dimension(),
                                 )  # TODO: Is this right?
        # Skipping TensorProductElement constructor! Bad code smell,
        # refactor to avoid this non-inheritance somehow.
        FiniteElementBase.__init__(self, family, cell, degree, quad_scheme,
                                   value_shape, reference_value_shape)

    def mapping(self):
        return "covariant Piola"

    def sobolev_space(self):
        "Return the underlying Sobolev space."
        return HCurl

    def reconstruct(self, **kwargs):
        return HCurlElement(self._element.reconstruct(**kwargs))

    def __str__(self):
        return "HCurlElement(%s)" % str(self._element)

    def shortstr(self):
        "Format as string for pretty printing."
        return "HCurlElement(%s)" % str(self._element.shortstr())
Exemple #23
0
class GeometricQuantity(Terminal):
    __slots__ = as_native_strings(("_domain", ))

    def __init__(self, domain):
        Terminal.__init__(self)
        self._domain = as_domain(domain)

    def ufl_domains(self):
        return (self._domain, )

    def is_cellwise_constant(self):
        "Return whether this expression is spatially constant over each cell (or over each facet for facet quantities)."
        # NB! Geometric quantities are piecewise constant by
        # default. Override if needed.
        return True

    # NB! Geometric quantities are scalar by default. Override if
    # needed.
    ufl_shape = ()

    def _ufl_signature_data_(self, renumbering):
        "Signature data of geometric quantities depend on the domain numbering."
        return (self._ufl_class_.__name__,
                ) + self._domain._ufl_signature_data_(renumbering)

    def __str__(self):
        return self._ufl_class_.name

    def __repr__(self):
        r = "%s(%s)" % (self._ufl_class_.__name__, repr(self._domain))
        return as_native_str(r)

    def _ufl_compute_hash_(self):
        return hash((type(self).__name__, ) + self._domain._ufl_hash_data_())

    def __eq__(self, other):
        return isinstance(other,
                          self._ufl_class_) and other._domain == self._domain
Exemple #24
0
class Label(Terminal):
    __slots__ = as_native_strings(("_count", ))

    _globalcount = 0

    def __init__(self, count=None):
        Terminal.__init__(self)
        counted_init(self, count, Label)

    def count(self):
        return self._count

    def __str__(self):
        return "Label(%d)" % self._count

    def __repr__(self):
        r = "Label(%d)" % self._count
        return as_native_str(r)

    @property
    def ufl_shape(self):
        error("Label has no shape (it is not a tensor expression).")

    @property
    def ufl_free_indices(self):
        error("Label has no free indices (it is not a tensor expression).")

    @property
    def ufl_index_dimensions(self):
        error("Label has no free indices (it is not a tensor expression).")

    def is_cellwise_constant(self):
        return True

    def ufl_domains(self):
        "Return tuple of domains related to this terminal object."
        return ()
Exemple #25
0
class ReferenceCurl(CompoundDerivative):
    __slots__ = as_native_strings(("ufl_shape",))

    def __new__(cls, f):
        # Validate input
        sh = f.ufl_shape
        if f.ufl_shape not in ((), (2,), (3,)):
            error("Expecting a scalar, 2D vector or 3D vector.")
        if f.ufl_free_indices:
            error("Free indices in the curl argument is not allowed.")

        # Return zero if expression is trivially constant
        if is_cellwise_constant(f):
            sh = {(): (2,), (2,): (), (3,): (3,)}[sh]
            return Zero(sh)  # No free indices asserted above
        return CompoundDerivative.__new__(cls)

    def __init__(self, f):
        global _curl_shapes
        CompoundDerivative.__init__(self, (f,))
        self.ufl_shape = _curl_shapes[f.ufl_shape]

    def __str__(self):
        return "reference_curl(%s)" % self.ufl_operands[0]
Exemple #26
0
class VariableDerivative(Derivative):
    __slots__ = as_native_strings((
        "ufl_shape",
        "ufl_free_indices",
        "ufl_index_dimensions",
    ))

    def __new__(cls, f, v):
        # Checks
        if not isinstance(f, Expr):
            error("Expecting an Expr in VariableDerivative.")
        if not isinstance(v, (Variable, Coefficient)):
            error("Expecting a Variable in VariableDerivative.")
        if v.ufl_free_indices:
            error("Differentiation variable cannot have free indices.")

        # Simplification
        # Return zero if expression is trivially independent of variable
        if f._ufl_is_terminal_ and f != v:
            return Zero(f.ufl_shape + v.ufl_shape, f.ufl_free_indices,
                        f.ufl_index_dimensions)

        # Construction
        return Derivative.__new__(cls)

    def __init__(self, f, v):
        Derivative.__init__(self, (f, v))
        self.ufl_free_indices = f.ufl_free_indices
        self.ufl_index_dimensions = f.ufl_index_dimensions
        self.ufl_shape = f.ufl_shape + v.ufl_shape

    def __str__(self):
        if isinstance(self.ufl_operands[0], Terminal):
            return "d%s/d[%s]" % (self.ufl_operands[0], self.ufl_operands[1])
        return "d/d[%s] %s" % (self.ufl_operands[1],
                               parstr(self.ufl_operands[0], self))
Exemple #27
0
# along with UFL. If not, see <http://www.gnu.org/licenses/>.
#
# Modified by Anders Logg, 2008-2009
# Modified by Massimiliano Leoni, 2016.

import ufl
from ufl.log import error
from ufl.core.expr import Expr
from ufl.checks import is_python_scalar, is_scalar_constant_expression
from ufl.measure import Measure  # noqa
from ufl.protocols import id_or_none
from ufl.utils.str import as_native_str
from ufl.utils.str import as_native_strings

# Export list for ufl.classes
__all_classes__ = as_native_strings(["Integral"])


class Integral(object):
    "An integral over a single domain."
    __slots__ = as_native_strings((
        "_integrand",
        "_integral_type",
        "_ufl_domain",
        "_subdomain_id",
        "_metadata",
        "_subdomain_data",
    ))

    def __init__(self, integrand, integral_type, domain, subdomain_id,
                 metadata, subdomain_data):
Exemple #28
0
# (at your option) any later version.
#
# UFL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with UFL. If not, see <http://www.gnu.org/licenses/>.

from ufl.utils.str import as_native_strings
from ufl.log import error
from ufl.finiteelement import FiniteElement, VectorElement, TensorElement, \
    MixedElement, EnrichedElement, NodalEnrichedElement

__all__ = as_native_strings(['increase_order', 'tear'])


def increase_order(element):
    "Return element of same family, but a polynomial degree higher."
    return _increase_degree(element, +1)


def change_regularity(element, family):
    """
    For a given finite element, return the corresponding space
    specified by 'family'.
    """
    return element.reconstruct(family=family)

Exemple #29
0
# Modified by Kristian B. Oelgaard, 2009
# Modified by Marie E. Rognes 2012
# Modified by Andrew T. T. McRae, 2014
# Modified by Massimiliano Leoni, 2016

import numbers
import functools

from ufl.utils.str import as_native_str
from ufl.utils.str import as_native_strings
from ufl.log import error
from ufl.core.ufl_type import attach_operators_from_hash_data


# Export list for ufl.classes
__all_classes__ = as_native_strings(["AbstractCell", "Cell", "TensorProductCell"])


# --- The most abstract cell class, base class for other cell types

class AbstractCell(object):
    """Representation of an abstract finite element cell with only the
    dimensions known.

    """
    __slots__ = as_native_strings(("_topological_dimension",
                                   "_geometric_dimension"))

    def __init__(self, topological_dimension, geometric_dimension):
        # Validate dimensions
        if not isinstance(geometric_dimension, numbers.Integral):
Exemple #30
0
# (at your option) any later version.
#
# UFL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with UFL. If not, see <http://www.gnu.org/licenses/>.

from ufl.log import error
from ufl.utils.str import as_native_str
from ufl.utils.str import as_native_strings

# Export list for ufl.classes
__all_classes__ = as_native_strings(["Equation"])


class Equation(object):
    """This class is used to represent equations expressed by the "=="
    operator. Examples include a == L and F == 0 where a, L and F are
    Form objects."""

    def __init__(self, lhs, rhs):
        "Create equation lhs == rhs"
        self.lhs = lhs
        self.rhs = rhs

    def __bool__(self):
        """Evaluate bool(lhs_form == rhs_form).
Exemple #31
0
import logging
from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL  # noqa: F401
from ufl.utils.str import as_native_strings

log_functions = ["log", "debug", "info", "deprecate", "warning", "error",
                 "begin", "end",
                 "set_level", "push_level", "pop_level", "set_indent",
                 "add_indent",
                 "set_handler", "get_handler", "get_logger", "add_logfile",
                 "set_prefix",
                 "info_red", "info_green", "info_blue",
                 "warning_red", "warning_green", "warning_blue"]

__all__ = as_native_strings(
    log_functions +
    ["Logger", "log_functions"] +
    ["DEBUG", "INFO", "DEPRECATE", "WARNING", "ERROR", "CRITICAL"]
)

DEPRECATE = (INFO + WARNING) // 2


# This is used to override emit() in StreamHandler for printing
# without newline
def emit(self, record):
    message = self.format(record)
    format_string = "%s" if getattr(record, "continued", False) else "%s\n"
    self.stream.write(format_string % message)
    self.flush()

Exemple #32
0
class IndexSum(Operator):
    __slots__ = as_native_strings((
        "_dimension",
        "ufl_free_indices",
        "ufl_index_dimensions",
    ))

    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)

    def __init__(self, summand, index):
        j, = index
        fi = summand.ufl_free_indices
        fid = summand.ufl_index_dimensions
        pos = fi.index(j.count())
        self._dimension = fid[pos]
        self.ufl_free_indices = fi[:pos] + fi[pos + 1:]
        self.ufl_index_dimensions = fid[:pos] + fid[pos + 1:]
        Operator.__init__(self, (summand, index))

    def index(self):
        return self.ufl_operands[1][0]

    def dimension(self):
        return self._dimension

    @property
    def ufl_shape(self):
        return self.ufl_operands[0].ufl_shape

    def evaluate(self, x, mapping, component, index_values):
        i, = self.ufl_operands[1]
        tmp = 0
        for k in range(self._dimension):
            index_values.push(i, k)
            tmp += self.ufl_operands[0].evaluate(x, mapping, component,
                                                 index_values)
            index_values.pop()
        return tmp

    def __str__(self):
        return "sum_{%s} %s " % (str(
            self.ufl_operands[1]), parstr(self.ufl_operands[0], self))
Exemple #33
0
#
# You should have received a copy of the GNU Lesser General Public License
# along with UFL. If not, see <http://www.gnu.org/licenses/>.
#
# Modified by Massimiliano Leoni, 2016.


from ufl.utils.str import as_native_str
from ufl.utils.str import as_native_strings
from ufl.log import error
from ufl.utils.counted import counted_init
from ufl.core.ufl_type import ufl_type
from ufl.core.terminal import Terminal

# Export list for ufl.classes
__all_classes__ = as_native_strings(["IndexBase", "FixedIndex", "Index"])


class IndexBase(object):
    """Base class for all indices."""
    __slots__ = ()

    def __init__(self):
        pass


class FixedIndex(IndexBase):
    """UFL value: An index with a specific value assigned."""
    __slots__ = as_native_strings(("_value", "_hash"))

    _cache = {}
Exemple #34
0
import sys
import types
import logging
from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL  # noqa: F401
from ufl.utils.str import as_native_strings

log_functions = [
    "log", "debug", "info", "deprecate", "warning", "error", "begin", "end",
    "set_level", "push_level", "pop_level", "set_indent", "add_indent",
    "set_handler", "get_handler", "get_logger", "add_logfile", "set_prefix",
    "info_red", "info_green", "info_blue", "warning_red", "warning_green",
    "warning_blue"
]

__all__ = as_native_strings(
    log_functions + ["Logger", "log_functions"] +
    ["DEBUG", "INFO", "DEPRECATE", "WARNING", "ERROR", "CRITICAL"])

DEPRECATE = (INFO + WARNING) // 2


# This is used to override emit() in StreamHandler for printing
# without newline
def emit(self, record):
    message = self.format(record)
    format_string = "%s" if getattr(record, "continued", False) else "%s\n"
    self.stream.write(format_string % message)
    self.flush()


# Colors if the terminal supports it (disabled e.g. when piped to
Exemple #35
0
# Modified by Marie E. Rognes 2012

import numbers

from ufl.utils.str import as_native_str
from ufl.utils.str import as_native_strings
from ufl.core.ufl_type import attach_operators_from_hash_data
from ufl.core.ufl_id import attach_ufl_id
from ufl.corealg.traversal import traverse_unique_terminals
from ufl.log import error
from ufl.cell import as_cell, AbstractCell, TensorProductCell
from ufl.finiteelement.tensorproductelement import TensorProductElement


# Export list for ufl.classes
__all_classes__ = as_native_strings(["AbstractDomain", "Mesh", "MeshView", "TensorProductMesh"])


class AbstractDomain(object):
    """Symbolic representation of a geometric domain with only a geometric
    and topological dimension.

    """

    def __init__(self, topological_dimension, geometric_dimension):
        # Validate dimensions
        if not isinstance(geometric_dimension, numbers.Integral):
            error("Expecting integer geometric dimension, not %s" % (geometric_dimension.__class__,))
        if not isinstance(topological_dimension, numbers.Integral):
            error("Expecting integer topological dimension, not %s" % (topological_dimension.__class__,))
        if topological_dimension > geometric_dimension:
Exemple #36
0
__all__ = as_native_strings([
    'product',
    'get_handler', 'get_logger', 'set_handler', 'set_level', 'add_logfile',
    'UFLException', 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL',
    'as_cell', 'AbstractCell', 'Cell', 'TensorProductCell',
    'as_domain', 'AbstractDomain', 'Mesh', 'MeshView', 'TensorProductMesh',
    'L2', 'H1', 'H2', 'HCurl', 'HDiv',
    'SpatialCoordinate',
    'CellVolume', 'CellDiameter', 'Circumradius',
    'MinCellEdgeLength', 'MaxCellEdgeLength',
    'FacetArea', 'MinFacetEdgeLength', 'MaxFacetEdgeLength',
    'FacetNormal', 'CellNormal',
    'Jacobian', 'JacobianDeterminant', 'JacobianInverse',
    'FiniteElementBase', 'FiniteElement',
    'MixedElement', 'VectorElement', 'TensorElement', 'EnrichedElement',
    'NodalEnrichedElement', 'RestrictedElement', 'TensorProductElement',
    'HDivElement', 'HCurlElement',
    'BrokenElement', 'FacetElement', 'InteriorElement',
    'register_element', 'show_elements',
    'FunctionSpace',
    'Argument', 'TestFunction', 'TrialFunction',
    'Arguments', 'TestFunctions', 'TrialFunctions',
    'Coefficient', 'Coefficients',
    'Constant', 'VectorConstant', 'TensorConstant',
    'split',
    'PermutationSymbol', 'Identity', 'zero', 'as_ufl',
    'Index', 'indices',
    'as_tensor', 'as_vector', 'as_matrix', 'relabel',
    'unit_vector', 'unit_vectors', 'unit_matrix', 'unit_matrices',
    'rank', 'shape', 'conj', 'real', 'imag', 
    'outer', 'inner', 'dot', 'cross', 'perp',
    'det', 'inv', 'cofac',
    'transpose', 'tr', 'diag', 'diag_vector', 'dev', 'skew', 'sym',
    'sqrt', 'exp', 'ln', 'erf',
    'cos', 'sin', 'tan',
    'acos', 'asin', 'atan', 'atan_2',
    'cosh', 'sinh', 'tanh',
    'bessel_J', 'bessel_Y', 'bessel_I', 'bessel_K',
    'eq', 'ne', 'le', 'ge', 'lt', 'gt', 'And', 'Or', 'Not',
    'conditional', 'sign', 'max_value', 'min_value', 'Max', 'Min',
    'variable', 'diff',
    'Dx', 'grad', 'div', 'curl', 'rot', 'nabla_grad', 'nabla_div', 'Dn', 'exterior_derivative',
    'jump', 'avg', 'cell_avg', 'facet_avg',
    'elem_mult', 'elem_div', 'elem_pow', 'elem_op',
    'Form',
    'Integral', 'Measure', 'register_integral_type', 'integral_types', 'custom_integral_types',
    'replace', 'replace_integral_domains', 'derivative', 'action', 'energy_norm', 'rhs', 'lhs', 'block_split',
    'system', 'functional', 'adjoint', 'sensitivity_rhs',
    'dx', 'ds', 'dS', 'dP',
    'dc', 'dC', 'dO', 'dI', 'dX',
    'ds_b', 'ds_t', 'ds_tb', 'ds_v', 'dS_h', 'dS_v',
    'vertex', 'interval', 'triangle', 'tetrahedron',
    'quadrilateral', 'hexahedron', 'facet',
    'i', 'j', 'k', 'l', 'p', 'q', 'r', 's',
    'e', 'pi',
])
Exemple #37
0
class Measure(object):
    __slots__ = as_native_strings(("_integral_type",
                                   "_domain",
                                   "_subdomain_id",
                                   "_metadata",
                                   "_subdomain_data"))
    """Representation of an integration measure.

    The Measure object holds information about integration properties
    to be transferred to a Form on multiplication with a scalar
    expression.

    """

    def __init__(self,
                 integral_type,  # "dx" etc
                 domain=None,
                 subdomain_id="everywhere",
                 metadata=None,
                 subdomain_data=None):
        """
        integral_type:
            str, one of "cell", etc.,
            or short form "dx", etc.

        domain:
            an AbstractDomain object (most often a Mesh)

        subdomain_id:
            either string "everywhere",
            a single subdomain id int,
            or tuple of ints

        metadata:
            dict, with additional compiler-specific parameters
            affecting how code is generated, including parameters
            for optimization or debugging of generated code.

        subdomain_data:
            object representing data to interpret subdomain_id with.
        """
        # Map short name to long name and require a valid one
        self._integral_type = as_integral_type(integral_type)

        # Check that we either have a proper AbstractDomain or none
        self._domain = None if domain is None else as_domain(domain)
        if not (self._domain is None or isinstance(self._domain, AbstractDomain)):
            error("Invalid domain.")

        # Store subdomain data
        self._subdomain_data = subdomain_data
        # FIXME: Cannot require this (yet) because we currently have
        # no way to implement ufl_id for dolfin SubDomain
        # if not (self._subdomain_data is None or hasattr(self._subdomain_data, "ufl_id")):
        #     error("Invalid domain data, missing ufl_id() implementation.")

        # Accept "everywhere", single subdomain, or multiple
        # subdomains
        if isinstance(subdomain_id, tuple):
            for did in subdomain_id:
                if not isinstance(did, numbers.Integral):
                    error("Invalid subdomain_id %s." % (did,))
        else:
            if not (subdomain_id in ("everywhere",) or isinstance(subdomain_id, numbers.Integral)):
                error("Invalid subdomain_id %s." % (subdomain_id,))
        self._subdomain_id = subdomain_id

        # Validate compiler options are None or dict
        if metadata is not None and not isinstance(metadata, dict):
            error("Invalid metadata.")
        self._metadata = metadata or EmptyDict

    def integral_type(self):
        """Return the domain type.

        Valid domain types are "cell", "exterior_facet", "interior_facet", etc.
        """
        return self._integral_type

    def ufl_domain(self):
        """Return the domain associated with this measure.

        This may be None or a Domain object.
        """
        return self._domain

    def subdomain_id(self):
        "Return the domain id of this measure (integer)."
        return self._subdomain_id

    def metadata(self):
        """Return the integral metadata. This data is not interpreted by UFL.
        It is passed to the form compiler which can ignore it or use
        it to compile each integral of a form in a different way.

        """
        return self._metadata

    def reconstruct(self,
                    integral_type=None,
                    subdomain_id=None,
                    domain=None,
                    metadata=None,
                    subdomain_data=None):
        """Construct a new Measure object with some properties replaced with
        new values.

        Example:
            <dm = Measure instance>
            b = dm.reconstruct(subdomain_id=2)
            c = dm.reconstruct(metadata={ "quadrature_degree": 3 })

        Used by the call operator, so this is equivalent:
            b = dm(2)
            c = dm(0, { "quadrature_degree": 3 })

        """
        if subdomain_id is None:
            subdomain_id = self.subdomain_id()
        if domain is None:
            domain = self.ufl_domain()
        if metadata is None:
            metadata = self.metadata()
        if subdomain_data is None:
            subdomain_data = self.subdomain_data()
        return Measure(self.integral_type(),
                       domain=domain, subdomain_id=subdomain_id,
                       metadata=metadata, subdomain_data=subdomain_data)

    def subdomain_data(self):
        """Return the integral subdomain_data. This data is not interpreted by
        UFL.  Its intension is to give a context in which the domain
        id is interpreted.

        """
        return self._subdomain_data

    # Note: Must keep the order of the first two arguments here
    # (subdomain_id, metadata) for backwards compatibility, because
    # some tutorials write e.g. dx(0, {...}) to set metadata.
    def __call__(self, subdomain_id=None, metadata=None, domain=None,
                 subdomain_data=None, degree=None, scheme=None, rule=None):
        """Reconfigure measure with new domain specification or metadata."""

        # Deprecation of 'rule' in favour of 'scheme'
        if rule is not None:
            deprecate("Measure argument 'rule' has been renamed to 'scheme'.")
            assert scheme is None or scheme == rule
            scheme = rule

        # Let syntax dx() mean integral over everywhere
        all_args = (subdomain_id, metadata, domain, subdomain_data,
                    degree, scheme)
        if all(arg is None for arg in all_args):
            return self.reconstruct(subdomain_id="everywhere")

        # Let syntax dx(domain) or dx(domain, metadata) mean integral
        # over entire domain.  To do this we need to hijack the first
        # argument:
        if subdomain_id is not None and (isinstance(subdomain_id,
                                                    AbstractDomain) or
                                         hasattr(subdomain_id, 'ufl_domain')):
            if domain is not None:
                error("Ambiguous: setting domain both as keyword argument and first argument.")
            subdomain_id, domain = "everywhere", as_domain(subdomain_id)

        # If degree or scheme is set, inject into metadata. This is a
        # quick fix to enable the dx(..., degree=3) notation.
        # TODO: Make degree and scheme properties of integrals instead of adding to metadata.
        if (degree, scheme) != (None, None):
            metadata = {} if metadata is None else metadata.copy()
            if degree is not None:
                metadata["quadrature_degree"] = degree
            if scheme is not None:
                metadata["quadrature_rule"] = scheme

        # If we get any keywords, use them to reconstruct Measure.
        # Note that if only one argument is given, it is the
        # subdomain_id, e.g. dx(3) == dx(subdomain_id=3)
        return self.reconstruct(subdomain_id=subdomain_id, domain=domain,
                                metadata=metadata,
                                subdomain_data=subdomain_data)

    def __getitem__(self, data):
        """This operator supports legacy syntax in python dolfin programs.

        The old documentation reads: Return a new Measure for same
        integration type with an attached context for interpreting
        domain ids. By default this new Measure integrates over
        everywhere, but it can be restricted with a domain id as
        usual. Example: dx = dx[boundaries]; L = f*v*dx + g*v+dx(1).

        """
        deprecate("Notation dx[meshfunction] is deprecated. Please use dx(subdomain_data=meshfunction) instead.")
        return self(subdomain_data=data)

    def __str__(self):
        global integral_type_to_measure_name
        name = integral_type_to_measure_name[self._integral_type]
        args = []

        if self._subdomain_id is not None:
            args.append("subdomain_id=%s" % (self._subdomain_id,))
        if self._domain is not None:
            args.append("domain=%s" % (self._domain,))
        if self._metadata:  # Stored as EmptyDict if None
            args.append("metadata=%s" % (self._metadata,))
        if self._subdomain_data is not None:
            args.append("subdomain_data=%s" % (self._subdomain_data,))

        return "%s(%s)" % (name, ', '.join(args))

    def __repr__(self):
        "Return a repr string for this Measure."
        global integral_type_to_measure_name

        args = []
        args.append(repr(self._integral_type))

        if self._subdomain_id is not None:
            args.append("subdomain_id=%s" % repr(self._subdomain_id))
        if self._domain is not None:
            args.append("domain=%s" % repr(self._domain))
        if self._metadata:  # Stored as EmptyDict if None
            args.append("metadata=%s" % repr(self._metadata))
        if self._subdomain_data is not None:
            args.append("subdomain_data=%s" % repr(self._subdomain_data))

        r = "%s(%s)" % (type(self).__name__, ', '.join(args))
        return as_native_str(r)

    def __hash__(self):
        "Return a hash value for this Measure."
        hashdata = (self._integral_type,
                    self._subdomain_id,
                    hash(self._domain),
                    metadata_hashdata(self._metadata),
                    id_or_none(self._subdomain_data))
        return hash(hashdata)

    def __eq__(self, other):
        "Checks if two Measures are equal."
        return (isinstance(other, Measure) and
                self._integral_type == other._integral_type and
                self._subdomain_id == other._subdomain_id and
                self._domain == other._domain and
                id_or_none(self._subdomain_data) == id_or_none(other._subdomain_data) and
                metadata_equal(self._metadata, other._metadata))

    def __add__(self, other):
        """Add two measures (self+other).

        Creates an intermediate object used for the notation

          expr * (dx(1) + dx(2)) := expr * dx(1) + expr * dx(2)
        """
        if isinstance(other, Measure):
            # Let dx(1) + dx(2) equal dx((1,2))
            return MeasureSum(self, other)
        else:
            # Can only add Measures
            return NotImplemented

    def __mul__(self, other):
        """Multiply two measures (self*other).

        Creates an intermediate object used for the notation

          expr * (dm1 * dm2) := expr * dm1 * dm2

        This is work in progress and not functional.
        """
        if isinstance(other, Measure):
            # Tensor product measure support
            return MeasureProduct(self, other)
        else:
            # Can't multiply Measure from the right with non-Measure type
            return NotImplemented

    def __rmul__(self, integrand):
        """Multiply a scalar expression with measure to construct a form with
        a single integral.

        This is to implement the notation

            form = integrand * self

        Integration properties are taken from this Measure object.

        """
        # Avoid circular imports
        from ufl.integral import Integral
        from ufl.form import Form

        # Allow python literals: 1*dx and 1.0*dx
        if isinstance(integrand, (int, float)):
            integrand = as_ufl(integrand)

        # Let other types implement multiplication with Measure if
        # they want to (to support the dolfin-adjoint TimeMeasure)
        if not isinstance(integrand, Expr):
            return NotImplemented

        # Allow only scalar integrands
        if not is_true_ufl_scalar(integrand):
            error("Can only integrate scalar expressions. The integrand is a "
                  "tensor expression with value shape %s and free indices with labels %s." %
                  (integrand.ufl_shape, integrand.ufl_free_indices))

        # If we have a tuple of domain ids, delegate composition to
        # Integral.__add__:
        subdomain_id = self.subdomain_id()
        if isinstance(subdomain_id, tuple):
            return sum(integrand*self.reconstruct(subdomain_id=d) for d in subdomain_id)

        # Check that we have an integer subdomain or a string
        # ("everywhere" or "otherwise", any more?)
        if not isinstance(subdomain_id, (str, numbers.Integral,)):
            error("Expecting integer or string domain id.")

        # If we don't have an integration domain, try to find one in
        # integrand
        domain = self.ufl_domain()
        if domain is None:
            domains = extract_domains(integrand)
            if len(domains) == 1:
                domain, = domains
            elif len(domains) == 0:
                error("This integral is missing an integration domain.")
            else:
                error("Multiple domains found, making the choice of integration domain ambiguous.")

        # Otherwise create and return a one-integral form
        integral = Integral(integrand=integrand,
                            integral_type=self.integral_type(),
                            domain=domain,
                            subdomain_id=subdomain_id,
                            metadata=self.metadata(),
                            subdomain_data=self.subdomain_data())
        return Form([integral])
Exemple #38
0
import numbers

from ufl.utils.str import as_native_strings
from ufl.utils.str import as_native_str
from ufl.log import error, deprecate
from ufl.core.expr import Expr
from ufl.checks import is_true_ufl_scalar
from ufl.constantvalue import as_ufl
from ufl.utils.dicts import EmptyDict
from ufl.domain import as_domain, AbstractDomain, extract_domains
from ufl.protocols import id_or_none, metadata_equal, metadata_hashdata


# Export list for ufl.classes
__all_classes__ = as_native_strings(["Measure", "MeasureSum", "MeasureProduct"])


# TODO: Design a class IntegralType(name, shortname, codim, num_cells, ...)?
# TODO: Improve descriptions below:

# Enumeration of valid domain types
_integral_types = [
    # === Integration over full topological dimension:
    ("cell", "dx"),                     # Over cells of a mesh
    # ("macro_cell", "dE"),              # Over a group of adjacent cells (TODO: Arbitrary cell group? Not currently used.)

    # === Integration over topological dimension - 1:
    ("exterior_facet", "ds"),           # Over one-sided exterior facets of a mesh
    ("interior_facet", "dS"),           # Over two-sided facets between pairs of adjacent cells of a mesh
Exemple #39
0
import ufl.finiteelement  # noqa E401
__all__ += populate_namespace_with_module_classes(ufl.finiteelement, locals())

import ufl.domain  # noqa E401
__all__ += populate_namespace_with_module_classes(ufl.domain, locals())

import ufl.functionspace  # noqa E401
__all__ += populate_namespace_with_module_classes(ufl.functionspace, locals())

import ufl.core.multiindex  # noqa E401
__all__ += populate_namespace_with_module_classes(ufl.core.multiindex, locals())

import ufl.argument  # noqa E401
__all__ += populate_namespace_with_module_classes(ufl.argument, locals())

import ufl.measure  # noqa E401
__all__ += populate_namespace_with_module_classes(ufl.measure, locals())

import ufl.integral  # noqa E401
__all__ += populate_namespace_with_module_classes(ufl.integral, locals())

import ufl.form  # noqa E401
__all__ += populate_namespace_with_module_classes(ufl.form, locals())

import ufl.equation  # noqa E401
__all__ += populate_namespace_with_module_classes(ufl.equation, locals())


__all__ = as_native_strings(__all__)
Exemple #40
0
from itertools import chain
from collections import defaultdict

from ufl.log import error, warning
from ufl.domain import sort_domains
from ufl.integral import Integral
from ufl.checks import is_scalar_constant_expression
from ufl.equation import Equation
from ufl.core.expr import Expr
from ufl.core.expr import ufl_err_str
from ufl.constantvalue import Zero
from ufl.utils.str import as_native_strings, as_native_str

# Export list for ufl.classes
__all_classes__ = as_native_strings(["Form"])

# --- The Form class, representing a complete variational form or functional ---


def _sorted_integrals(integrals):
    """Sort integrals by domain id, integral type, subdomain id
    for a more stable signature computation."""

    # Group integrals in multilevel dict by keys
    # [domain][integral_type][subdomain_id]
    integrals_dict = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
    for integral in integrals:
        d = integral.ufl_domain()
        if d is None:
            error("Each integral in a form must have a uniquely defined integration domain.")
Exemple #41
0
__all__ = as_native_strings([
    "estimate_total_polynomial_degree",
    "sort_elements",
    "compute_form_data",
    "purge_list_tensors",
    "apply_transformer",
    "ReuseTransformer",
    "load_ufl_file",
    "Transformer",
    "MultiFunction",
    "extract_unique_elements",
    "extract_type",
    "extract_elements",
    "extract_sub_elements",
    "preprocess_expression",
    "expand_indices",
    "replace",
    "expand_derivatives",
    "extract_coefficients",
    "strip_variables",
    "post_traversal",
    "change_to_reference_grad",
    "expand_compounds",
    "validate_form",
    "ufl2latex",
    "FormSplitter",
    "extract_arguments",
    "compute_form_adjoint",
    "compute_form_action",
    "compute_energy_norm",
    "compute_form_lhs",
    "compute_form_rhs",
    "compute_form_functional",
    "compute_form_signature",
    "tree_format",
])
Exemple #42
0
# Modified by Anders Logg, 2008-2009.
# Modified by Massimiliano Leoni, 2016.

import numbers
from ufl.utils.str import as_native_str
from ufl.utils.str import as_native_strings
from ufl.log import error
from ufl.core.ufl_type import ufl_type
from ufl.core.terminal import FormArgument
from ufl.split_functions import split
from ufl.finiteelement import FiniteElementBase
from ufl.domain import default_domain
from ufl.functionspace import AbstractFunctionSpace, FunctionSpace

# Export list for ufl.classes (TODO: not actually classes: drop? these are in ufl.*)
__all_classes__ = as_native_strings(["TestFunction", "TrialFunction", "TestFunctions", "TrialFunctions"])


# --- Class representing an argument (basis function) in a form ---

@ufl_type()
class Argument(FormArgument):
    """UFL value: Representation of an argument to a form."""
    __slots__ = as_native_strings((
        "_ufl_function_space",
        "_ufl_shape",
        "_number",
        "_part",
        "_repr",
    ))