Ejemplo n.º 1
0
Archivo: checks.py Proyecto: FEniCS/ufl
def is_globally_constant(expr):
    """Check if an expression is globally constant, which
    includes spatially independent constant coefficients that
    are not known before assembly time."""
    # TODO: This does not consider gradients of coefficients, so false
    # negatives are possible.
    # from ufl.argument import Argument
    # from ufl.coefficient import Coefficient
    from ufl.geometry import GeometricQuantity
    from ufl.core.terminal import FormArgument
    for e in traverse_unique_terminals(expr):
        # Return False if any single terminal is not constant
        if e._ufl_is_literal_:
            # Accept literals first, they are the most common
            # terminals
            continue
        elif isinstance(e, FormArgument):
            # Accept only Real valued Arguments and Coefficients
            if e.ufl_element().family() == "Real":
                continue
            else:
                return False
        elif isinstance(e, GeometricQuantity):
            # Reject all geometric quantities, they all vary over
            # cells
            return False

    # All terminals passed constant check
    return True
Ejemplo n.º 2
0
def is_globally_constant(expr):
    """Check if an expression is globally constant, which
    includes spatially independent constant coefficients that
    are not known before assembly time."""
    # TODO: This does not consider gradients of coefficients, so false
    # negatives are possible.
    # from ufl.argument import Argument
    # from ufl.coefficient import Coefficient
    from ufl.geometry import GeometricQuantity
    from ufl.core.terminal import FormArgument
    for e in traverse_unique_terminals(expr):
        # Return False if any single terminal is not constant
        if e._ufl_is_literal_:
            # Accept literals first, they are the most common
            # terminals
            continue
        elif isinstance(e, FormArgument):
            # Accept only Real valued Arguments and Coefficients
            if e.ufl_element().family() == "Real":
                continue
            else:
                return False
        elif isinstance(e, GeometricQuantity):
            # Reject all geometric quantities, they all vary over
            # cells
            return False

    # All terminals passed constant check
    return True
Ejemplo n.º 3
0
def _generate_space(expression: Operator):
    # Extract mesh from expression (from dolfin/fem/projection.py, _extract_function_space function)
    meshes = set(
        [ufl_domain.ufl_cargo() for ufl_domain in extract_domains(expression)])
    for t in traverse_unique_terminals(
            expression):  # from ufl/domain.py, extract_domains
        if hasattr(t, "_mesh"):
            meshes.add(t._mesh)
    assert len(meshes) == 1
    mesh = meshes.pop()
    # The EIM algorithm will evaluate the expression at vertices. However, since the Operator expression may
    # contain e.g. a gradient of a solution defined in a C^0 space, we resort to DG1 spaces.
    shape = expression.ufl_shape
    assert len(shape) in (0, 1, 2)
    if len(shape) == 0:
        space = FunctionSpace(mesh, "Discontinuous Lagrange", 1)
    elif len(shape) == 1:
        space = VectorFunctionSpace(mesh,
                                    "Discontinuous Lagrange",
                                    1,
                                    dim=shape[0])
    elif len(shape) == 2:
        space = TensorFunctionSpace(mesh,
                                    "Discontinuous Lagrange",
                                    1,
                                    shape=shape)
    else:
        raise ValueError(
            "Invalid expression in ParametrizedExpressionFactory.__init__().")
    return space
Ejemplo n.º 4
0
def _extract_arguments(form):
    # This is a copy of extract_type in ufl.algorithms.analysis
    # without wrapping the result in a set
    return [
        o for e in iter_expressions(form) for o in traverse_unique_terminals(e)
        if isinstance(o, Argument)
    ]
    def __init__(self, expr, locations, mesh=None):
        # Extract mesh from one of the arguments
        if mesh is None:
            for arg in traverse_unique_terminals(expr):
                print arg
                if isinstance(arg, Function):
                    mesh = arg.function_space().mesh()
                    break
        assert mesh is not None

        expr = icompile(expr)
        size = expr.ufl_element().value_size()

        limit = mesh.num_entities(mesh.topology().dim())
        bbox_tree = mesh.bounding_box_tree()

        evals = []
        for x in locations:
            cell = bbox_tree.compute_first_entity_collision(Point(*x))

            if -1 < cell < limit:
                foo = lambda x=x, expr=expr: (expr)(x)
            else:
                foo = lambda size=size: (np.finfo(float).max) * np.ones(size)
            evals.append(foo)

        self.probes = evals
        # Return the value in the shape of vector/matrix
        self.nprobes = len(locations)
Ejemplo n.º 6
0
 def _basic_expression_name(expression):
     str_repr = ""
     coefficients_replacement = dict()
     # Preprocess indices first, as their numeric value might change from run to run, but they
     # are always sorted the same way
     indices = set()
     min_index = None
     for t in traverse_unique_terminals(expression):
         if isinstance(t, MultiIndex):
             for i in t.indices():
                 if isinstance(i, MuteIndex):
                     if min_index is None or i.count() < min_index:
                         min_index = i.count()
                     indices.add(i)
     for i in indices:
         coefficients_replacement[repr(i)] = "MuteIndexRBniCS(" + str(i.count() - min_index) + ")"
     # Process the expression
     visited = set()
     for n in wrapping.expression_iterator(expression):
         if n in visited:
             continue
         if hasattr(n, "_cppcode"):
             coefficients_replacement[repr(n)] = str(n._cppcode)
             str_repr += repr(n._cppcode)
             visited.add(n)
         elif wrapping.is_problem_solution_type(n):
             if wrapping.is_problem_solution(n):
                 (preprocessed_n, component, truth_solution) = wrapping.solution_identify_component(n)
                 problem = get_problem_from_solution(truth_solution)
                 coefficients_replacement[repr(preprocessed_n)] = "solution of " + str(problem.name()) + " (exact problem decorator: " + str(hasattr(problem, "__is_exact__")) + ", component: " + str(component) + ")"
             elif wrapping.is_problem_solution_dot(n):
                 (preprocessed_n, component, truth_solution_dot) = wrapping.solution_dot_identify_component(n)
                 problem = get_problem_from_solution_dot(truth_solution_dot)
                 coefficients_replacement[repr(preprocessed_n)] = "solution_dot of " + str(problem.name()) + " (exact problem decorator: " + str(hasattr(problem, "__is_exact__")) + ", component: " + str(component) + ")"
             else:
                 (preprocessed_n, component, problem) = wrapping.get_auxiliary_problem_for_non_parametrized_function(n)
                 coefficients_replacement[repr(preprocessed_n)] = "non parametrized function associated to auxiliary problem " + str(problem.name())
             if len(component) == 1 and component[0] is not None:
                 coefficients_replacement[repr(preprocessed_n)] += ", component " + str(component[0])
             elif len(component) > 1:
                 coefficients_replacement[repr(preprocessed_n)] += ", component " + str(component)
             str_repr += coefficients_replacement[repr(preprocessed_n)]
             # Make sure to skip any parent solution related to this one
             visited.add(n)
             visited.add(preprocessed_n)
             for parent_n in wrapping.solution_iterator(preprocessed_n):
                 visited.add(parent_n)
         elif isinstance(n, Constant):
             vals = n.values()
             coefficients_replacement[repr(n)] = str(vals)
             str_repr += repr(str(vals))
             visited.add(n)
         else:
             str_repr += repr(n)
             visited.add(n)
     for key, value in coefficients_replacement.items():
         str_repr = str_repr.replace(key, value)
     hash_code = hashlib.sha1(str_repr.encode("utf-8")).hexdigest()
     return hash_code
Ejemplo n.º 7
0
 def nonlinear_operator(self, o):
     # Cutoff traversal by not having *ops in argument list of this
     # handler.  Traverse only the terminals under here the fastest
     # way we know of:
     for t in traverse_unique_terminals(o):
         if t._ufl_typecode_ == Argument._ufl_typecode_:
             raise ArityMismatch("Applying nonlinear operator {0} to expression depending on form argument {1}.".format(o._ufl_class_.__name__, t))
     return self._et
Ejemplo n.º 8
0
def is_extension_integrand(expr, tdim):
    '''Some of the arguments need extension'''
    if tdim == 2:
        return any((topological_dim(arg)+1) == tdim
                   for arg in traverse_unique_terminals(expr))
    
    # Line extends to line
    top_crit = any(topological_dim(arg) == tdim
                   for arg in traverse_unique_terminals(expr))
    # This is not quite enough because a regular fenics integral might be
    # like this if the meshes of the terminals are the same. So we check
    # for difference
    mesh_ids = set(t.ufl_domain().ufl_cargo().id()
                   for t in traverse_unique_terminals(expr)
                   if topological_dim(t) == tdim)
    
    return top_crit and len(mesh_ids) > 1 
Ejemplo n.º 9
0
def compute_terminal_hashdata(expressions, renumbering):

    if not isinstance(expressions, list):
        expressions = [expressions]
    assert renumbering is not None

    # Extract a unique numbering of free indices, as well as form
    # arguments, and just take repr of the rest of the terminals while
    # we're iterating over them
    terminal_hashdata = {}
    labels = {}
    index_numbering = {}
    for expression in expressions:
        for expr in traverse_unique_terminals(expression):

            if isinstance(expr, MultiIndex):
                # Indices need a canonical numbering for a stable
                # signature, thus this algorithm
                data = compute_multiindex_hashdata(expr, index_numbering)

            elif isinstance(expr, ConstantValue):
                data = expr._ufl_signature_data_(renumbering)

            elif isinstance(expr, Coefficient):
                data = expr._ufl_signature_data_(renumbering)

            elif isinstance(expr, Constant):
                data = expr._ufl_signature_data_(renumbering)

            elif isinstance(expr, Argument):
                data = expr._ufl_signature_data_(renumbering)

            elif isinstance(expr, GeometricQuantity):
                data = expr._ufl_signature_data_(renumbering)

            elif isinstance(expr, Label):
                # Numbering labels as we visit them # TODO: Include in
                # renumbering
                data = labels.get(expr)
                if data is None:
                    data = "L%d" % len(labels)
                    labels[expr] = data

            elif isinstance(expr, ExprList):
                # Not really a terminal but can have 0 operands...
                data = "[]"

            elif isinstance(expr, ExprMapping):
                # Not really a terminal but can have 0 operands...
                data = "{}"

            else:
                error("Unknown terminal type %s" % type(expr))

            terminal_hashdata[expr] = data

    return terminal_hashdata
Ejemplo n.º 10
0
 def nonlinear_operator(self, o):
     # Cutoff traversal by not having *ops in argument list of this
     # handler.  Traverse only the terminals under here the fastest
     # way we know of:
     for t in traverse_unique_terminals(o):
         if t._ufl_typecode_ == Argument._ufl_typecode_:
             raise ArityMismatch(
                 "Applying nonlinear operator {0} to expression depending on form argument {1}."
                 .format(o._ufl_class_.__name__, t))
     return self._et
Ejemplo n.º 11
0
def compute_terminal_hashdata(expressions, renumbering):

    if not isinstance(expressions, list):
        expressions = [expressions]
    assert renumbering is not None

    # Extract a unique numbering of free indices, as well as form
    # arguments, and just take repr of the rest of the terminals while
    # we're iterating over them
    terminal_hashdata = {}
    labels = {}
    index_numbering = {}
    for expression in expressions:
        for expr in traverse_unique_terminals(expression):

            if isinstance(expr, MultiIndex):
                # Indices need a canonical numbering for a stable
                # signature, thus this algorithm
                data = compute_multiindex_hashdata(expr, index_numbering)

            elif isinstance(expr, ConstantValue):
                data = expr._ufl_signature_data_(renumbering)

            elif isinstance(expr, Coefficient):
                data = expr._ufl_signature_data_(renumbering)

            elif isinstance(expr, Argument):
                data = expr._ufl_signature_data_(renumbering)

            elif isinstance(expr, GeometricQuantity):
                data = expr._ufl_signature_data_(renumbering)

            elif isinstance(expr, Label):
                # Numbering labels as we visit them # TODO: Include in
                # renumbering
                data = labels.get(expr)
                if data is None:
                    data = "L%d" % len(labels)
                    labels[expr] = data

            elif isinstance(expr, ExprList):
                # Not really a terminal but can have 0 operands...
                data = "[]"

            elif isinstance(expr, ExprMapping):
                # Not really a terminal but can have 0 operands...
                data = "{}"

            else:
                error("Unknown terminal type %s" % type(expr))

            terminal_hashdata[expr] = data

    return terminal_hashdata
Ejemplo n.º 12
0
def extract_type(a, ufl_type):
    """Build a set of all objects of class ufl_type found in a.
    The argument a can be a Form, Integral or Expr."""
    if issubclass(ufl_type, Terminal):
        # Optimization
        return set(o for e in iter_expressions(a)
                   for o in traverse_unique_terminals(e)
                   if isinstance(o, ufl_type))
    else:
        return set(o for e in iter_expressions(a)
                   for o in unique_pre_traversal(e) if isinstance(o, ufl_type))
Ejemplo n.º 13
0
    def space_for(expr, shape=None):
        '''Function space where expr should be represented'''
        # Don't want to call eval here as it beats the goal of being lazy
        foos = filter(lambda f: isinstance(f, Function),
                      traverse_unique_terminals(expr))
        _, = set(f.function_space().mesh().id() for f in foos)

        elm = common_sub_element([f.function_space() for f in foos])
        shape = expr.ufl_shape if shape is None else shape
        mesh = foos[0].function_space().mesh()

        return make_space(elm, shape, mesh)
Ejemplo n.º 14
0
def _check_timederiv(o: TimeDerivative, self: Memoizer) -> Result:
    op, = o.ufl_operands
    if self(op):
        # op already has a TimeDerivative applied to it
        raise ValueError("Can only handle first-order systems")
    terminals = tuple(
        set([
            x for x in traverse_unique_terminals(op)
            if not isinstance(x, MultiIndex)
        ]))
    if len(terminals) != 1 or not isinstance(terminals[0], Coefficient):
        raise ValueError("Time derivative must apply to a single coefficient")
    return terminals
Ejemplo n.º 15
0
def _check_facet_geometry(integral_data):
    for itg_data in integral_data:
        for itg in itg_data.integrals:
            it = itg_data.integral_type
            # Facet geometry is only valid in facet integrals.
            # Allowing custom integrals to pass as well, although
            # that's not really strict enough.
            if not ("facet" in it or "custom" in it or "interface" in it):
                # Not a facet integral
                for expr in traverse_unique_terminals(itg.integrand()):
                    cls = expr._ufl_class_
                    if issubclass(cls, GeometricFacetQuantity):
                        error("Integral of type %s cannot contain a %s." % (it, cls.__name__))
Ejemplo n.º 16
0
def _check_facet_geometry(integral_data):
    for itg_data in integral_data:
        for itg in itg_data.integrals:
            it = itg_data.integral_type
            # Facet geometry is only valid in facet integrals.
            # Allowing custom integrals to pass as well, although
            # that's not really strict enough.
            if not ("facet" in it or "custom" in it or "interface" in it):
                # Not a facet integral
                for expr in traverse_unique_terminals(itg.integrand()):
                    cls = expr._ufl_class_
                    if issubclass(cls, GeometricFacetQuantity):
                        error("Integral of type %s cannot contain a %s." % (it, cls.__name__))
Ejemplo n.º 17
0
 def __init__(self, func, other):
     super().__init__()
     self.other = None
     self.expr = None
     if isinstance(other, float) or isinstance(other, int):
         other = AdjFloat(other)
     if isinstance(other, OverloadedType):
         self.add_dependency(other, no_duplicates=True)
     elif not (isinstance(other, float) or isinstance(other, int)):
         # Assume that this is a point-wise evaluated UFL expression (firedrake only)
         for op in traverse_unique_terminals(other):
             if isinstance(op, OverloadedType):
                 self.add_dependency(op, no_duplicates=True)
         self.expr = other
Ejemplo n.º 18
0
def series_rule(expr):
    '''Eval expression where the terminals are time series'''
    # Make first sure that the series are compatible in the sense
    # of having same f and time interval
    times = timeseries.common_interval(list(traverse_unique_terminals(expr)))
    assert len(times)

    series = map(Interpreter.eval, expr.ufl_operands)

    # We apply the op to functions in the series and construct a new one
    args = izip(*[s if isinstance(s, timeseries.TempSeries) else repeat(Interpreter.eval(s)) 
                  for s in series])

    functions = [Interpreter.eval(apply(type(expr), arg)) for arg in args]

    return timeseries.TempSeries(zip(functions, times))
Ejemplo n.º 19
0
def find_geometric_dimension(expr):
    "Find the geometric dimension of an expression."
    gdims = set()
    for t in traverse_unique_terminals(expr):
        if hasattr(t, "ufl_domain"):
            domain = t.ufl_domain()
            if domain is not None:
                gdims.add(domain.geometric_dimension())
        if hasattr(t, "ufl_element"):
            element = t.ufl_element()
            if element is not None:
                cell = element.cell()
                if cell is not None:
                    gdims.add(cell.geometric_dimension())
    if len(gdims) != 1:
        error("Cannot determine geometric dimension from expression.")
    gdim, = gdims
    return gdim
Ejemplo n.º 20
0
def is_injection_integral(integral):
    '''
    Cell integral over domain that is that over domain that has child
    '''
    if not integral.integral_type() == 'cell':
        return False

    fmesh = integral.ufl_domain().ufl_cargo()

    if not is_injection_integrand(integral.integrand()):
        return False

    for arg in filter(is_injection,
                      traverse_unique_terminals(integral.integrand())):
        if arg.injection_['mesh'].id() == fmesh.id():
            return True

    return False
Ejemplo n.º 21
0
def find_geometric_dimension(expr):
    "Find the geometric dimension of an expression."
    gdims = set()
    for t in traverse_unique_terminals(expr):
        if hasattr(t, "ufl_domain"):
            domain = t.ufl_domain()
            if domain is not None:
                gdims.add(domain.geometric_dimension())
        if hasattr(t, "ufl_element"):
            element = t.ufl_element()
            if element is not None:
                cell = element.cell()
                if cell is not None:
                    gdims.add(cell.geometric_dimension())
    if len(gdims) != 1:
        error("Cannot determine geometric dimension from expression.")
    gdim, = gdims
    return gdim
Ejemplo n.º 22
0
def is_restriction_integral(integral):
    '''
    A restriction integral here is:
    1) the measure is defined over a subdomain mesh
    2) in the parent map of the mesh we find a mesh of at least on argument
       of the integrand
    '''
    # Domain of the measure
    restriction_domain = integral.ufl_domain().ufl_cargo()
    if not isinstance(restriction_domain, SubDomainMesh):
        return False
    
    mapping = restriction_domain.parent_entity_map

    for t in traverse_unique_terminals(integral.integrand()):
        # Of argument
        domain = t.ufl_domain()
        if domain is not None:
            mesh = domain.ufl_cargo()
            if mesh.id() in mapping:
                return True
    return False
Ejemplo n.º 23
0
    def eval(expr):
        # Terminals/base cases (also TempSeries)
        if isinstance(expr, Interpreter.terminal_type): return expr

        if isinstance(expr, Interpreter.value_type): return expr.value()
        
        # Okay: now we have expr with arguments. If this expression involves 
        # times series then all the non number arguments should be compatible 
        # time series
        terminals = filter(lambda t: isinstance(t, Function), traverse_unique_terminals(expr))
        # Don't mix function and terminals
        series = filter(lambda t: isinstance(t, timeseries.TempSeries), terminals)

        assert len(series) == len(terminals) or len(series) == 0, map(len, (series, terminals))
        # For series, we apply op to functions and make new series
        if series:
            assert not isinstance(expr, Interpreter.index_type)
            return series_rule(expr)

        expr_type = type(expr)
        # Require reshaping and all args are functions
        if expr_type in Interpreter.reshape_type: 
            return numpy_reshaped(expr, op=Interpreter.reshape_type[expr_type])

        # Indexing [] is special as the second argument gives slicing
        if isinstance(expr, Interpreter.index_type): return indexed_rule(expr)

        # No reshaping neeed
        op = Interpreter.no_reshape_type[expr_type]  # Throw if we don't support this

        args = map(Interpreter.eval, expr.ufl_operands)
        # Manipulate coefs of arguments to get coefs of the expression
        coefs = map(coefs_of, args)
        V_coefs = op(*coefs)    
        # Make that function
        V = space_of(args)

        return make_function(V, V_coefs)
Ejemplo n.º 24
0
def series_rule(expr):
    '''Eval expression where the terminals are time series'''
    foos = filter(lambda f: isinstance(f, Function),
                  traverse_unique_terminals(expr))
    # Make first sure that the series are compatible in the sense of having same time
    # interval
    times = timeseries.common_interval(foos)
    assert len(times)

    # Compatibility of spaces
    common_sub_element([f.function_space() for f in foos])

    # The idea now is to propagate the expression by which I mean that
    # we grow the expr using nodes in the series
    def unpack(expr):
        '''expr -> iterable of expr'''
        return (apply(type(expr), sum(args, ()))
                for args in expand(expr.ufl_operands))

    def expand(operands):
        iterators = []
        for o in operands:
            if isinstance(o, timeseries.TempSeries):
                iterators.append(((f, ) for f in o))
            # Nonseries terminal
            elif not o.ufl_operands:
                iterators.append(((f, ) for f in repeat(o)))
            # An expression
            else:
                iterators.append(((f, ) for f in unpack(o)))

        return izip(*iterators)

    nodes = unpack(expr)
    # A series of new nodes -> series of functions
    return Interpreter.eval(timeseries.TempSeries(zip(nodes, times)))
Ejemplo n.º 25
0
    def assemble(self, form, arity):
        '''Assemble a biliner(2), linear(1) form'''
        reduced_integrals = self.select_integrals(form)  #! Selector
        # Signal to xii.assemble
        if not reduced_integrals: return None

        components = []
        for integral in form.integrals():
            # Delegate to friend
            if integral not in reduced_integrals:
                components.append(
                    xii.assembler.xii_assembly.assemble(Form([integral])))
                continue

            reduced_mesh = integral.ufl_domain().ufl_cargo()

            integrand = integral.integrand()
            # Split arguments in those that need to be and those that are
            # already restricted.
            terminals = set(traverse_unique_terminals(integrand))

            # FIXME: is it enough info (in general) to decide
            terminals_to_restrict = sorted(
                self.restriction_filter(terminals, reduced_mesh),
                key=lambda t: self.is_compatible(t, reduced_mesh))
            # You said this is a trace ingral!
            assert terminals_to_restrict

            # Let's pick a guy for restriction
            terminal = terminals_to_restrict.pop()
            # We have some assumption on the candidate
            assert self.is_compatible(terminal, reduced_mesh)

            data = self.reduction_matrix_data(terminal)

            integrand = ufl2uflcopy(integrand)
            # With sane inputs we can get the reduced element and setup the
            # intermediate function space where the reduction of terminal
            # lives
            V = terminal.function_space()
            TV = self.reduced_space(V, reduced_mesh)  #! Space construc

            # Setup the matrix to from space of the trace_terminal to the
            # intermediate space. FIXME: normal and trace_mesh
            #! mat construct
            df.info('\tGetting reduction op')
            rop_timer = df.Timer('rop')
            T = self.reduction_matrix(V, TV, reduced_mesh, data)
            df.info('\tDone (reduction op) %g' % rop_timer.stop())
            # T
            if is_test_function(terminal):
                replacement = df.TestFunction(TV)
                # Passing the args to get the comparison a make substitution
                integrand = replace(integrand,
                                    terminal,
                                    replacement,
                                    attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])

                if arity == 2:
                    # Make attempt on the substituted form
                    A = xii.assembler.xii_assembly.assemble(trace_form)
                    components.append(block_transpose(T) * A)
                else:
                    b = xii.assembler.xii_assembly.assemble(trace_form)
                    Tb = df.Function(V).vector()  # Alloc and apply
                    T.transpmult(b, Tb)
                    components.append(Tb)

            if is_trial_function(terminal):
                assert arity == 2
                replacement = df.TrialFunction(TV)
                # Passing the args to get the comparison
                integrand = replace(integrand,
                                    terminal,
                                    replacement,
                                    attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])

                A = xii.assembler.xii_assembly.assemble(trace_form)
                components.append(A * T)

            # Okay, then this guy might be a function
            if isinstance(terminal, df.Function):
                replacement = df.Function(TV)
                # Replacement is not just a placeholder
                T.mult(terminal.vector(), replacement.vector())
                # Substitute
                integrand = replace(integrand,
                                    terminal,
                                    replacement,
                                    attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])
                components.append(
                    xii.assembler.xii_assembly.assemble(trace_form))

        # The whole form is then the sum of integrals
        return reduce(operator.add, components)
Ejemplo n.º 26
0
def is_trace_integrand(expr, tdim):
    '''Some of the arguments need restriction'''
    return any((topological_dim(arg)-1)  == tdim
               for arg in traverse_unique_terminals(expr))
Ejemplo n.º 27
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)
Ejemplo n.º 28
0
def extract_domains(expr):
    "Return all domains expression is defined on."
    domainlist = []
    for t in traverse_unique_terminals(expr):
        domainlist.extend(t.ufl_domains())
    return sorted(join_domains(domainlist))
Ejemplo n.º 29
0
def extract_domains(expr):
    "Return all domains expression is defined on."
    domainlist = []
    for t in traverse_unique_terminals(expr):
        domainlist.extend(t.ufl_domains())
    return sorted(join_domains(domainlist))
Ejemplo n.º 30
0
    def eval(expr):
        # Guys with their own logic for collapsing into functions
        # Okay we combine 2 design patters, LazyNodes do it themselves
        # series rely on the interpreter
        if isinstance(expr, operators.LazyNode):
            return expr.evaluate()

        # For series we eval each node and make a series of functions
        # NOTE: intersept here because TempSeries is a terminal type
        if isinstance(expr, timeseries.TempSeries):
            return timeseries.TempSeries(
                zip(map(Interpreter.eval, expr), expr.times))

        # Terminals/base cases (also TempSeries) -> identity
        if isinstance(expr, Interpreter.terminal_type): return expr

        # To number
        if isinstance(expr, Interpreter.value_type): return expr.value()

        # To number
        if isinstance(expr, Constant): return float(expr)

        # To number
        if isinstance(expr, ufl.constantvalue.Zero): return 0

        # Recast spatial coordinate as CG1 functions
        if isinstance(expr, ufl.geometry.SpatialCoordinate):
            mesh = expr.ufl_domain().ufl_cargo()
            r = Expression(('x[0]', 'x[1]', 'x[2]')[:mesh.geometry().dim()],
                           degree=1)
            return interpolate(r, VectorFunctionSpace(mesh, 'CG', 1))

        # Okay: now we have expr with arguments. If this expression involves
        # times series then all the non number arguments should be compatible
        # time series
        terminals = filter(lambda t: isinstance(t, Function),
                           traverse_unique_terminals(expr))
        # Don't mix function and terminals
        series = filter(lambda t: isinstance(t, timeseries.TempSeries),
                        terminals)

        assert len(series) == len(terminals) or len(series) == 0, map(
            type, terminals)
        # For series, we apply op to functions and make new series
        if series:
            return series_rule(expr)

        expr_type = type(expr)
        # Require reshaping and all args are functions
        if expr_type in Interpreter.reshape_type:
            return numpy_reshaped(expr, op=Interpreter.reshape_type[expr_type])

        # Clement
        if expr_type in Interpreter.diff_type:
            # NOTE: Clement is its own thing-it does not use this interpreter
            # for subexpression evaluation
            return clement_interpolate(expr)

        # Define tensor by componenents
        if isinstance(expr, Interpreter.compose_type):
            return component_tensor_rule(expr)

        # A indexed by FixedIndex or Index
        if isinstance(expr, Interpreter.index_type):
            return indexed_rule(expr)

        # No reshaping neeed
        op = Interpreter.no_reshape_type[
            expr_type]  # Throw if we don't support this

        args = map(Interpreter.eval, expr.ufl_operands)
        # Manipulate coefs of arguments to get coefs of the expression
        coefs = map(coefs_of, args)
        V_coefs = op(*coefs)
        # Make that function
        V = space_of(args)

        return make_function(V, V_coefs)
Ejemplo n.º 31
0
def is_cellwise_constant(expr):
    "Return whether expression is constant over a single cell."
    # TODO: Implement more accurately considering e.g. derivatives?
    return all(t.is_cellwise_constant() for t in traverse_unique_terminals(expr))
Ejemplo n.º 32
0
def is_point_trace_integral(integral):
    '''A point trace integral is one where some argument is a point trace.'''
    return any(hasattr(t, 'dirac_') for t in traverse_unique_terminals(integral.integrand()))
Ejemplo n.º 33
0
Archivo: checks.py Proyecto: FEniCS/ufl
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)
Ejemplo n.º 34
0
def is_restriction_integrand(expr):
    '''Is it?'''
    return any((is_restriction(arg) for arg in traverse_unique_terminals(expr)))
Ejemplo n.º 35
0
def is_average_integrand(expr, tdim):
    '''Some of the arguments need restriction'''
    return any((topological_dim(arg) == tdim + 2) and isinstance(arg, Argument)
               for arg in traverse_unique_terminals(expr))
Ejemplo n.º 36
0
    def assemble(self, form, arity):
        '''Assemble a biliner(2), linear(1) form'''
        reduced_integrals = self.select_integrals(form)   #! Selector
        # Signal to xii.assemble
        if not reduced_integrals: return None
    
        components = []
        for integral in form.integrals():
            # Delegate to friend
            if integral not in reduced_integrals:
                components.append(xii.assembler.xii_assembly.assemble(Form([integral])))
                continue

            reduced_mesh = integral.ufl_domain().ufl_cargo()

            integrand = integral.integrand()
            # Split arguments in those that need to be and those that are
            # already restricted.
            terminals = set(traverse_unique_terminals(integrand))

            # FIXME: is it enough info (in general) to decide
            terminals_to_restrict = self.restriction_filter(terminals, reduced_mesh)
            # You said this is a trace ingral!
            assert terminals_to_restrict

            # Let's pick a guy for restriction
            terminal = terminals_to_restrict.pop()
            # We have some assumption on the candidate
            assert self.is_compatible(terminal, reduced_mesh)

            data = self.reduction_matrix_data(terminal)
                
            integrand = ufl2uflcopy(integrand)
            # With sane inputs we can get the reduced element and setup the
            # intermediate function space where the reduction of terminal
            # lives
            V = terminal.function_space()
            TV = self.reduced_space(V, reduced_mesh)  #! Space construc

            # Setup the matrix to from space of the trace_terminal to the
            # intermediate space. FIXME: normal and trace_mesh
            #! mat construct
            T = self.reduction_matrix(V, TV, reduced_mesh, data)

            # T
            if is_test_function(terminal):
                replacement = df.TestFunction(TV)
                # Passing the args to get the comparison a make substitution
                integrand = replace(integrand, terminal, replacement, attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])

                if arity == 2:
                    # Make attempt on the substituted form
                    A = xii.assembler.xii_assembly.assemble(trace_form)
                    components.append(block_transpose(T)*A)
                else:
                    b = xii.assembler.xii_assembly.assemble(trace_form)
                    Tb = df.Function(V).vector()  # Alloc and apply
                    T.transpmult(b, Tb)
                    components.append(Tb)

            if is_trial_function(terminal):
                assert arity == 2
                replacement = df.TrialFunction(TV)
                # Passing the args to get the comparison
                integrand = replace(integrand, terminal, replacement, attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])

                A = xii.assembler.xii_assembly.assemble(trace_form)
                components.append(A*T)

            # Okay, then this guy might be a function
            if isinstance(terminal, df.Function):
                replacement = df.Function(TV)
                # Replacement is not just a placeholder
                T.mult(terminal.vector(), replacement.vector())
                # Substitute
                integrand = replace(integrand, terminal, replacement, attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])
                components.append(xii.assembler.xii_assembly.assemble(trace_form))

        # The whole form is then the sum of integrals
        return reduce(operator.add, components)
Ejemplo n.º 37
0
def is_average_integrand(expr, tdim):
    '''Some of the arguments need restriction'''
    return any((topological_dim(arg) == tdim + 2) and isinstance(arg, Argument)
               for arg in traverse_unique_terminals(expr))
Ejemplo n.º 38
0
def is_trace_integrand(expr, tdim):
    '''Some of the arguments need restriction'''
    return any((topological_dim(arg) - 1) == tdim
               for arg in traverse_unique_terminals(expr))
Ejemplo n.º 39
0
Archivo: checks.py Proyecto: FEniCS/ufl
def is_cellwise_constant(expr):
    "Return whether expression is constant over a single cell."
    # TODO: Implement more accurately considering e.g. derivatives?
    return all(t.is_cellwise_constant() for t in traverse_unique_terminals(expr))