def project_firedrake(v, V, **kwargs):

    annotate = kwargs.pop("annotate", None)

    to_annotate = utils.to_annotate(annotate)

    if isinstance(v, backend.Expression) and (annotate is not True):
        to_annotate = False

    if isinstance(v, backend.Constant) and (annotate is not True):
        to_annotate = False

    if isinstance(V, backend.functionspaceimpl.WithGeometry):
        result = utils.function_to_da_function(backend.Function(V, name=None))
    elif isinstance(V, backend.function.Function):
        result = utils.function_to_da_function(V)
    else:
        raise ValueError("Can't project into a '%r'" % V)

    name = kwargs.pop("name", None)
    if name is not None:
        result.adj_name = name
        result.rename(name, "a Function from dolfin-adjoint")
    with misc.annotations(to_annotate):
        result = backend.project(v, result, **kwargs)

    return result
Beispiel #2
0
def project(*args, **kwargs):
    """The project call performs an equation solve, and so it too must be annotated so that the
    adjoint and tangent linear models may be constructed automatically by pyadjoint.

    To disable the annotation of this function, just pass :py:data:`annotate=False`. This is useful in
    cases where the solve is known to be irrelevant or diagnostic for the purposes of the adjoint
    computation (such as projecting fields to other function spaces for the purposes of
    visualisation)."""

    ad_block_tag = kwargs.pop("ad_block_tag", None)
    annotate = annotate_tape(kwargs)
    with stop_annotating():
        output = backend.project(*args, **kwargs)
    output = create_overloaded_object(output)

    if annotate:
        bcs = kwargs.pop("bcs", [])
        sb_kwargs = ProjectBlock.pop_kwargs(kwargs)
        sb_kwargs.update(kwargs)
        block = ProjectBlock(args[0],
                             args[1],
                             output,
                             bcs,
                             ad_block_tag=ad_block_tag,
                             **sb_kwargs)

        tape = get_working_tape()
        tape.add_block(block)

        block.add_output(output.block_variable)

    return output
Beispiel #3
0
def project_firedrake(v, V, **kwargs):

    annotate = kwargs.pop("annotate", None)

    to_annotate = utils.to_annotate(annotate)

    if isinstance(v, backend.Expression) and (annotate is not True):
        to_annotate = False

    if isinstance(v, backend.Constant) and (annotate is not True):
        to_annotate = False

    if isinstance(V, backend.functionspaceimpl.WithGeometry):
        result = utils.function_to_da_function(backend.Function(V, name=None))
    elif isinstance(V, backend.function.Function):
        result = utils.function_to_da_function(V)
    else:
        raise ValueError("Can't project into a '%r'" % V)

    name = kwargs.pop("name", None)
    if name is not None:
        result.adj_name = name
        result.rename(name, "a Function from dolfin-adjoint")
    with misc.annotations(to_annotate):
        result = backend.project(v, result, **kwargs)

    return result
def project_firedrake(*args, **kwargs):

  try:
    annotate = kwargs["annotate"]
    kwargs.pop("annotate")
  except KeyError:
    annotate = None

  to_annotate = utils.to_annotate(annotate)

  if isinstance(args[0], backend.Expression) and (annotate is not True):
    to_annotate = False

  if isinstance(args[0], backend.Constant) and (annotate is not True):
    to_annotate = False

  if to_annotate:
    result = backend.project(*args, **kwargs)
  else:
    flag = misc.pause_annotation()
    result = backend.project(*args, **kwargs)
    misc.continue_annotation(flag)

  return result
def project_dolfin(v, V=None, bcs=None, mesh=None, solver_type="cg", preconditioner_type="default", form_compiler_parameters=None, annotate=None, name=None):
    '''The project call performs an equation solve, and so it too must be annotated so that the
    adjoint and tangent linear models may be constructed automatically by libadjoint.

    To disable the annotation of this function, just pass :py:data:`annotate=False`. This is useful in
    cases where the solve is known to be irrelevant or diagnostic for the purposes of the adjoint
    computation (such as projecting fields to other function spaces for the purposes of
    visualisation).'''

    to_annotate = utils.to_annotate(annotate)

    if isinstance(v, backend.Expression) and (annotate is not True):
        to_annotate = False

    if isinstance(v, backend.Constant) and (annotate is not True):
        to_annotate = False

    out = backend.project(v=v, V=V, bcs=bcs, mesh=mesh, solver_type=solver_type, preconditioner_type=preconditioner_type, form_compiler_parameters=form_compiler_parameters)
    out = utils.function_to_da_function(out)

    if name is not None:
        out.adj_name = name
        out.rename(name, "a Function from dolfin-adjoint")

    if to_annotate:
        # reproduce the logic from project. This probably isn't future-safe, but anyway

        if V is None:
            V = backend.fem.projection._extract_function_space(v, mesh)
        if mesh is None:
            mesh = V.mesh()

        # Define variational problem for projection
        w = backend.TestFunction(V)
        Pv = backend.TrialFunction(V)
        a = backend.inner(w, Pv)*backend.dx(domain=mesh)
        L = backend.inner(w, v)*backend.dx(domain=mesh)

        solving.annotate(a == L, out, bcs, solver_parameters={"linear_solver": solver_type, "preconditioner": preconditioner_type, "symmetric": True})

        if backend.parameters["adjoint"]["record_all"]:
            adjglobals.adjointer.record_variable(adjglobals.adj_variables[out], libadjoint.MemoryStorage(adjlinalg.Vector(out)))

    return out
    def evaluate_tlm_component(self,
                               inputs,
                               tlm_inputs,
                               block_variable,
                               idx,
                               prepared=None):
        bc = block_variable.saved_output
        for bv in self.get_dependencies():
            tlm_input = bv.tlm_value

            if tlm_input is None:
                continue

            if self.function_space != self.parent_space and not isinstance(
                    tlm_input, ufl.Coefficient):
                tlm_input = backend.project(tlm_input, self.collapsed_space)

            # TODO: This is gonna crash for dirichletbcs with multiple dependencies (can't add two bcs)
            #       However, if there is multiple dependencies, we need to AD the expression (i.e if value=f*g then
            #       dvalue = tlm_f * g + f * tlm_g). Right now we can only handle value=f => dvalue = tlm_f.
            m = compat.create_bc(bc, value=tlm_input)
        return m
Beispiel #7
0
    def evaluate_hessian_component(self,
                                   inputs,
                                   hessian_inputs,
                                   adj_inputs,
                                   block_variable,
                                   idx,
                                   relevant_dependencies,
                                   prepared=None):
        hessian_inputs = hessian_inputs[0]
        adj_inputs = adj_inputs[0]
        c1 = block_variable.output

        if c1 not in self.expression.user_defined_derivatives:
            return None

        first_deriv = self.expression.user_defined_derivatives[c1]
        for key in self.expression._ad_attributes_dict:
            if key not in self.expression.ad_ignored_attributes:
                setattr(first_deriv, key,
                        self.expression._ad_attributes_dict[key])

        hessian_output = None
        for _, bo2 in relevant_dependencies:
            c2 = bo2.output
            tlm_input = bo2.tlm_value

            if tlm_input is None:
                continue

            if c2 not in first_deriv.user_defined_derivatives:
                continue

            second_deriv = first_deriv.user_defined_derivatives[c2]
            for key in self.expression._ad_attributes_dict:
                if key not in self.expression.ad_ignored_attributes:
                    setattr(second_deriv, key,
                            self.expression._ad_attributes_dict[key])

            for adj_pair in adj_inputs:
                adj_input = adj_pair[0]
                V = adj_pair[1]

                if hessian_output is None:
                    hessian_output = 0.0

                # TODO: Seems we can only project and not interpolate ufl.algebra.Product in dolfin.
                #       Consider the difference and which actually makes sense here.
                interp = backend.project(tlm_input * second_deriv, V)
                if isinstance(c1, (backend.Constant, AdjFloat)):
                    hessian_output += adj_input.inner(interp.vector())
                else:
                    vec = adj_input * interp.vector()
                    hessian_func = backend.Function(V, vec)

                    num_sub_spaces = V.num_sub_spaces()
                    if num_sub_spaces > 1:
                        for i in range(num_sub_spaces):
                            hessian_output += backend.interpolate(
                                hessian_func.sub(i),
                                c1.function_space()).vector()
                    else:
                        hessian_output += backend.interpolate(
                            hessian_func, c1.function_space()).vector()

        for hessian_pair in hessian_inputs:
            if hessian_output is None:
                hessian_output = 0.0
            hessian_input = hessian_pair[0]
            V = hessian_pair[1]

            interp = backend.interpolate(first_deriv, V)
            if isinstance(c1, (backend.Constant, AdjFloat)):
                hessian_output += hessian_input.inner(interp.vector())
            else:
                vec = hessian_input * interp.vector()
                hessian_func = backend.Function(V, vec)

                num_sub_spaces = V.num_sub_spaces()
                if num_sub_spaces > 1:
                    for i in range(num_sub_spaces):
                        hessian_output += backend.interpolate(
                            hessian_func.sub(i), c1.function_space()).vector()
                else:
                    hessian_output += backend.interpolate(
                        hessian_func, c1.function_space()).vector()
        return hessian_output
Beispiel #8
0
def project_dolfin(v,
                   V=None,
                   bcs=None,
                   mesh=None,
                   solver_type="lu",
                   preconditioner_type="default",
                   form_compiler_parameters=None,
                   annotate=None,
                   name=None):
    '''The project call performs an equation solve, and so it too must be annotated so that the
    adjoint and tangent linear models may be constructed automatically by libadjoint.

    To disable the annotation of this function, just pass :py:data:`annotate=False`. This is useful in
    cases where the solve is known to be irrelevant or diagnostic for the purposes of the adjoint
    computation (such as projecting fields to other function spaces for the purposes of
    visualisation).'''

    to_annotate = utils.to_annotate(annotate)

    if isinstance(v, backend.Expression) and (annotate is not True):
        to_annotate = False

    if isinstance(v, backend.Constant) and (annotate is not True):
        to_annotate = False

    out = backend.project(v=v,
                          V=V,
                          bcs=bcs,
                          mesh=mesh,
                          solver_type=solver_type,
                          preconditioner_type=preconditioner_type,
                          form_compiler_parameters=form_compiler_parameters)
    out = utils.function_to_da_function(out)

    if name is not None:
        out.adj_name = name
        out.rename(name, "a Function from dolfin-adjoint")

    if to_annotate:
        # reproduce the logic from project. This probably isn't future-safe, but anyway

        if V is None:
            V = backend.fem.projection._extract_function_space(v, mesh)
        if mesh is None:
            mesh = V.mesh()

        # Define variational problem for projection
        w = backend.TestFunction(V)
        Pv = backend.TrialFunction(V)
        a = backend.inner(w, Pv) * backend.dx(domain=mesh)
        L = backend.inner(w, v) * backend.dx(domain=mesh)

        solving.annotate(a == L,
                         out,
                         bcs,
                         solver_parameters={
                             "linear_solver": solver_type,
                             "preconditioner": preconditioner_type,
                             "symmetric": True
                         })

        if backend.parameters["adjoint"]["record_all"]:
            adjglobals.adjointer.record_variable(
                adjglobals.adj_variables[out],
                libadjoint.MemoryStorage(adjlinalg.Vector(out)))

    return out
Beispiel #9
0
def project(args):
    backend.project(args.phid)
Beispiel #10
0
    def axpy(self, alpha, x):

        if hasattr(x, 'nonlinear_form'):
            self.nonlinear_form = x.nonlinear_form
            self.nonlinear_u = x.nonlinear_u
            self.nonlinear_bcs = x.nonlinear_bcs
            self.nonlinear_J = x.nonlinear_J

        if x.zero:
            return

        if (self.data is None):
            # self is an empty form.
            if isinstance(x.data, backend.Function):
                self.data = x.data.copy(deepcopy=True)
                self.data.vector()._scale(alpha)
            if isinstance(x.data, backend.MultiMeshFunction):
                self.data = backend.MultiMeshFunction(x.data.function_space(),
                        x.data.vector())
                self.data.vector()._scale(alpha)
            else:
                self.data=alpha*x.data

        elif x.data is None:
            pass
        elif isinstance(self.data, backend.Coefficient):
            if isinstance(x.data, backend.Coefficient):
                try:
                    self.data.vector().axpy(alpha, x.data.vector())
                except:
                    # Handle subfunctions
                    # Fixme: use FunctionAssigner instead of a projection
                    #assigner = backend.FunctionAssigner(self.data.function_space,
                    #        x.data.function_space()
                    x = backend.project(x.data, self.data.function_space())
                    self.data.vector().axpy(alpha, x.vector())
            else:
                # This occurs when adding a RHS derivative to an adjoint equation
                # corresponding to the initial conditions.
                if ((len(x.data.coefficients())>0) and
                    hasattr(x.data.coefficients()[0], '_V')):
                    self.data.vector().axpy(alpha,
                                            backend.assemble_multimesh(x.data))
                else:
                    self.data.vector().axpy(alpha, backend.assemble(x.data))
                self.data.form = alpha * x.data
        elif isinstance(x.data, ufl.form.Form) and isinstance(self.data, ufl.form.Form):

            # Let's do a bit of argument shuffling, shall we?
            xargs = ufl.algorithms.extract_arguments(x.data)
            sargs = ufl.algorithms.extract_arguments(self.data)

            if xargs != sargs:
                # OK, let's check that all of the function spaces are happy and so on.
                for i in range(len(xargs)):
                    assert xargs[i].element() == sargs[i].element()
                    assert xargs[i].function_space() == sargs[i].function_space()

                # Now that we are happy, let's replace the xargs with the sargs ones.
                x_form = backend.replace(x.data, dict(zip(xargs, sargs)))
            else:
                x_form = x.data

            self.data+=alpha*x_form
        elif isinstance(self.data, ufl.form.Form) and isinstance(x.data, backend.Function):
            #print "axpy assembling FormFunc. self.data is a %s; x.data is a %s" % (self.data.__class__, x.data.__class__)
            x_vec = x.data.vector().copy()
            self_vec = backend.assemble(self.data)
            self_vec.axpy(alpha, x_vec)
            new_fn = backend.Function(x.data.function_space())
            new_fn.vector()[:] = self_vec
            self.data = new_fn
            self.fn_space = self.data.function_space()
        elif isinstance(self.data, backend.MultiMeshFunction):
            raise NotImplementedError

        else:
            print "self.data.__class__: ", self.data.__class__
            print "x.data.__class__: ", x.data.__class__
            assert False

        self.zero = False
Beispiel #11
0
    def derivative(self, adjointer, variable, dependencies, values):
        if self.verbose:
            for dep in dependencies:
                print(variable.timestep, "derive wrt ", dep.name)
        if self.regform is not None and variable.name == self.regform.coefficients(
        )[0].name():  # derivative wrt the contorl
            if self.verbose: " derivatives wrt the controls "
            raise RuntimeError("""The derivative of a regularisation term
                                  doesn't work properly and shouldn't be used"""
                               )
            return self.regfunc.derivative(adjointer, variable, dependencies,
                                           values)
        else:
            # transate finish_time: UGLY!!
            if "FINISH_TIME" in self.times:
                final_time = _time_levels(adjointer,
                                          adjointer.timestep_count - 1)[1]
                self.times[self.times.index("FINISH_TIME")] = final_time

            if self.verbose:
                print("derive ", variable.timestep, " num values ",
                      len(values))
            timesteps = self._derivative_timesteps(adjointer, variable)

            ff = [backend.Constant(0.0)] * len(self.coords)
            for i in range(len(self.coords)):
                if self.skip[i]:
                    if self.verbose: print("skipped")
                else:
                    if len(timesteps
                           ) is 1:  # only occurs at start and finish time
                        tsoi = timesteps[-1]
                        if tsoi is 0:
                            toi = _time_levels(adjointer, tsoi)[0]
                            ind = -1
                        else:
                            toi = _time_levels(adjointer, tsoi)[-1]
                            ind = 0
                    else:
                        if len(values) is 1:  # one value (easy)
                            tsoi = timesteps[-1]
                            toi = _time_levels(adjointer, tsoi)[0]
                            ind = 0
                        elif len(values) is 2:  # two values (hard)
                            tsoi = timesteps[-1]
                            toi = _time_levels(adjointer, tsoi)[0]
                            if _time_levels(adjointer, tsoi)[1] in self.times:
                                ind = 0
                            else:
                                ind = 1
                        else:  # three values (easy)
                            tsoi = timesteps[1]
                            toi = _time_levels(adjointer, tsoi)[0]
                            ind = 1
                    coef = values[ind].data
                    ref = self.refs[i][self.times.index(toi)]
                    if self.index[i] is None: solu = coef(self.coords[i])
                    else: solu = coef(self.coords[i])[self.index[i]]
                    ff[i] = backend.Constant(self.alpha * 2.0 *
                                             (solu - float(ref)))

            # Set up linear combinations to be projected
            form = ff[0] * self.basis[0]
            for i in range(1, len(self.coords)):
                form += ff[i] * self.basis[i]

            v = backend.project(form, self.func.function_space())

            return adjlinalg.Vector(v)