Exemplo n.º 1
0
    def add(self, form):
        '''self[i][j] += form with i, j extracted'''
        if len(form.integrals()) > 1:
            return map(self.add, [ufl.Form((i, )) for i in form.integrals()])

        # Linear
        if self.arity == 1:
            assert trial_function(form) == ()

            test_f, = test_function(form)  # Only one
            # Look for the index
            V = test_f.function_space()
            i, _ = next(
                dropwhile(lambda (i, Vi), V=V: Vi != V, enumerate(self.V0)))

            self[i] += form
            return self

        # Bilinear
        test_f, = test_function(form)  # Only one
        trial_f, = trial_function(form)  # Only one

        V = trial_f.function_space()
        col, _ = next(
            dropwhile(lambda (i, Vi), V=V: Vi != V, enumerate(self.V0)))

        V = test_f.function_space()
        row, _ = next(
            dropwhile(lambda (i, Vi), V=V: Vi != V, enumerate(self.V0)))

        self[row][col] += form
        return self
Exemplo n.º 2
0
def coarsen_form(form, coefficient_mapping=None):
    """Return a coarse mesh version of a form

    :arg form: The :class:`~ufl.classes.Form` to coarsen.
    :kwarg mapping: an optional map from coefficients to their
        coarsened equivalents.

    This maps over the form and replaces coefficients and arguments
    with their coarse mesh equivalents."""
    if form is None:
        return None

    mapper = CoarsenIntegrand(coefficient_mapping)
    integrals = []
    for it in form.integrals():
        integrand = map_expr_dag(mapper, it.integrand())
        mesh = it.ufl_domain()
        hierarchy, level = utils.get_level(mesh)
        new_mesh = hierarchy[level-1]
        if isinstance(integrand, ufl.classes.Zero):
            continue
        if it.subdomain_data() is not None:
            raise CoarseningError("Don't know how to coarsen subdomain data")
        new_itg = it.reconstruct(integrand=integrand,
                                 domain=new_mesh)
        integrals.append(new_itg)
    return ufl.Form(integrals)
Exemplo n.º 3
0
def form_adjoint(expr):
    '''Like UFL adjoint but keeping track of ii attributes'''
    if is_number(expr):
        return expr

    if isinstance(expr, ufl.Form):
        return ufl.Form(map(form_adjoint, expr.integrals()))

    if isinstance(expr, ufl.Integral):
        return expr.reconstruct(integrand=form_adjoint(expr.integrand()))

    # For adjoint we need one trial and one test function. The idea is
    # then exchange the two while keeping track of trace attributes
    arguments = set(
        filter(lambda f: isinstance(f, Argument), traverse_terminals(expr)))

    ii_attrs = ('trace_', 'restriction_', 'average_')

    adj_type = {0: TrialFunction, 1: TestFunction}
    for arg in arguments:
        adj_arg = adj_type[arg.number()](arg.function_space())
        # Record trace attributes
        attrs = []
        for attr in ii_attrs:
            if hasattr(arg, attr):
                setattr(adj_arg, attr, getattr(arg, attr))
                attrs.append(attr)
        # Substitute
        expr = ii_replace(expr, arg, adj_arg, attrs)

    return expr
Exemplo n.º 4
0
    def adjoint_derivative_action(self, nl_deps, dep_index, adj_x):
        # Derived from EquationSolver.derivative_action (see dolfin-adjoint
        # reference below). Code first added 2017-12-07.
        # Re-written 2018-01-28
        # Updated to adjoint only form 2018-01-29

        eq_deps = self.dependencies()
        if dep_index < 0 or dep_index >= len(eq_deps):
            raise EquationException("dep_index out of bounds")
        elif dep_index == 0:
            return adj_x

        dep = eq_deps[dep_index]
        dF = derivative(self._rhs, dep)
        dF = ufl.algorithms.expand_derivatives(dF)
        dF = eliminate_zeros(dF)
        if dF.empty():
            return None

        dF = self._nonlinear_replace(dF, nl_deps)
        if self._rank == 0:
            dF = ufl.Form([integral.reconstruct(integrand=ufl.conj(integral.integrand()))  # noqa: E501
                           for integral in dF.integrals()])  # dF = adjoint(dF)
            dF = assemble(
                dF, form_compiler_parameters=self._form_compiler_parameters)
            return (-function_scalar_value(adj_x), dF)
        else:
            assert self._rank == 1
            dF = assemble(
                ufl.action(adjoint(dF), coefficient=adj_x),
                form_compiler_parameters=self._form_compiler_parameters)
            return (-1.0, dF)
Exemplo n.º 5
0
def test_expression_derivative(V1, V2, squaremesh_5):

    u1, du1, v1 = dolfinx.fem.Function(V1), ufl.TrialFunction(
        V1), ufl.TestFunction(V1)
    u2, du2, v2 = dolfinx.fem.Function(V2), ufl.TrialFunction(
        V2), ufl.TestFunction(V2)

    dx = ufl.dx(squaremesh_5)

    # Test derivative of expressions

    assert dolfiny.expression.derivative(1 * u1, u1, du1) == 1 * du1
    assert dolfiny.expression.derivative(2 * u1 + u2, u1, du1) == 2 * du1
    assert dolfiny.expression.derivative(u1**2 + u2, u1, du1) == du1 * 2 * u1

    assert dolfiny.expression.derivative(u1 + u2, [u1, u2],
                                         [v1, v2]) == v1 + v2
    assert dolfiny.expression.derivative([u1, u2], u1, v1) == [v1, 0]
    assert dolfiny.expression.derivative([u1, u2], [u1, u2],
                                         [v1, v2]) == [v1, v2]

    # Test derivative of forms

    assert dolfiny.expression.derivative(1 * u1 * dx, u1, du1) == 1 * du1 * dx
    assert dolfiny.expression.derivative(2 * u1 * dx + u2 * dx, u1,
                                         du1) == 2 * du1 * dx
    assert dolfiny.expression.derivative(u1**2 * dx + u2 * dx, u1,
                                         du2) == du2 * 2 * u1 * dx

    assert dolfiny.expression.derivative(u1 * dx + u2 * dx, [u1, u2],
                                         [v1, v2]) == v1 * dx + v2 * dx
    assert dolfiny.expression.derivative([u1 * dx, u2 * dx], u1,
                                         v1) == [v1 * dx,
                                                 ufl.Form([])]
    assert dolfiny.expression.derivative([u1 * dx, u2 * dx], [u1, u2],
                                         [v1, v2]) == [v1 * dx, v2 * dx]

    # Test derivative of expressions at u0

    u10, u20 = dolfinx.fem.Function(V1), dolfinx.fem.Function(V2)

    assert dolfiny.expression.derivative(1 * u1, u1, du1, u0=u10) == 1 * du1
    assert dolfiny.expression.derivative(2 * u1 + u2, u1, du1,
                                         u0=u10) == 2 * du1
    assert dolfiny.expression.derivative(u1**2 + u2, u1, du1,
                                         u0=u10) == du1 * 2 * u10

    assert dolfiny.expression.derivative(
        u1**2 + u2**2, [u1, u2], [v1, v2],
        [u10, u20]) == v1 * 2 * u10 + v2 * 2 * u20
    assert dolfiny.expression.derivative([u1**2, u2], u1, v1,
                                         u0=u10) == [v1 * 2 * u10, 0]
    assert dolfiny.expression.derivative(
        [u1**2 + u2, u2], [u1, u2], [v1, v2],
        [u10, u20]) == [v1 * 2 * u10 + v2, v2]
Exemplo n.º 6
0
def adaptform_OLD(form, mesh, adapt_coefficients=False):
    oldmesh = form.domain().data()
    if (oldmesh.id() == mesh.id()):
        return form
    # define new domain
    newdomain = mesh.ufl_domain()
    # adapt meshfunctions
    newsubdata = form.subdomain_data().values()[0]  # assuming single domain
    for k, meshfunction in newsubdata.items():
        newsubdata[k] = adaptmeshfunction(meshfunction, mesh)

    # replace domain, meshfunctions in integrals
    integrals = []
    for itg in form.integrals():
        newitg = itg.reconstruct(
            domain=newdomain, subdomain_data=newsubdata[itg.integral_type()])
        integrals.append(newitg)
    newform = ufl.Form(integrals)

    # replace arguments and coefficients in form
    mapping = {}
    # adapt arguments
    for argument in form.arguments():
        newargument = adaptargument(argument, mesh)
        mapping[argument] = newargument
    if (adapt_coefficients):
        # adapt coefficients
        for coeff in form.coefficients():
            adaptcoefficient(coeff, mesh)  #MOD
            #newcoeff = adaptcoefficient(coeff,mesh)
            #mapping[coeff] = newcoeff

    # TODO: is there more? is there a better way to ensure everything is adapted?
    # adapt FacetNormal
    mapping[FacetNormal(oldmesh)] = FacetNormal(mesh)
    # adapt CellSize -- have to use ufl.Circumradius or replace() complains
    mapping[ufl.Circumradius(oldmesh)] = ufl.Circumradius(mesh)

    newform = replace(newform, mapping)
    return newform
Exemplo n.º 7
0
def ii_derivative(f, x):
    '''DOLFIN's derivative df/dx extended to handle trace stuff'''
    test_f = is_okay_functional(f)

    # FIXME: for now don't allow diffing wrt compound expressions, in particular
    # restricted args.
    assert isinstance(x, ufl.Coefficient) and not is_restricted(x)

    # So now we have L(arg, v) where arg = (u, ..., T[u], Pi[u], ...) and the idea
    # is to define derivative w.r.t to x by doing
    # J = sum_{arg} (partial L / partial arg){arg=T[u]}(partial arg / partial x).
    J = 0
    # NOTE: in the following I try to avoid assembly of zero forms because
    # these might not be well-defined for xii assembler. Also, assembling
    # zeros is useless
    for fi in [c for c in f.coefficients() if not isinstance(c, df.Constant)]:
        # Short circuit if (partial fi)/(partial x) is 0
        if not ((fi == x) or fi.vector().id() == x.vector().id()): continue

        if is_restricted(fi):
            rtype = restriction_type(fi)
            attributes = (rtype, )
        else:
            rtype = ''
            attributes = None
        fi_sub = df.Function(fi.function_space())

        # To recreate the form for partial we sub in every integral of f
        sub_form_integrals = []
        for integral in f.integrals():

            integrand = ii_replace(integral.integrand(), fi, fi_sub,
                                   attributes)
            # If the substitution is do nothing then there's no need to diff
            if integrand != integral.integrand():
                sub_form_integrals.append(
                    integral.reconstruct(integrand=integrand))
        sub_form = ufl.Form(sub_form_integrals)

        # Partial wrt to substituated argument
        df_dfi = df.derivative(sub_form, fi_sub)

        # Substitue back the original form argument
        sub_form_integrals = []
        for integral in df_dfi.integrals():
            integrand = ii_replace(integral.integrand(), fi_sub, fi)
            assert integrand != integral.integrand()
            sub_form_integrals.append(
                integral.reconstruct(integrand=integrand))
        df_dfi = ufl.Form(sub_form_integrals)

        # As d Tu / dx = T(x) we now need to restrict the trial function
        if rtype:
            trial_f = get_trialfunction(df_dfi)
            setattr(trial_f, rtype, getattr(fi, rtype))
        # Since we only allos diff wrt to coef then in the case rtype == ''
        # we have dfi/dx = 1

        J += df_dfi
    # Done
    return J