Beispiel #1
0
    def prepare_evaluate_hessian(self, inputs, hessian_inputs, adj_inputs,
                                 relevant_dependencies):
        # First fetch all relevant values
        fwd_block_variable = self.get_outputs()[0]
        hessian_input = hessian_inputs[0]
        tlm_output = fwd_block_variable.tlm_value

        if hessian_input is None:
            return

        if tlm_output is None:
            return

        F_form = self._create_F_form()

        # Using the equation Form we derive dF/du, d^2F/du^2 * du/dm * direction.
        dFdu_form = backend.derivative(F_form, fwd_block_variable.saved_output)
        d2Fdu2 = ufl.algorithms.expand_derivatives(
            backend.derivative(dFdu_form, fwd_block_variable.saved_output,
                               tlm_output))

        adj_sol = self.adj_sol
        if adj_sol is None:
            raise RuntimeError("Hessian computation was run before adjoint.")
        bdy = self._should_compute_boundary_adjoint(relevant_dependencies)
        adj_sol2, adj_sol2_bdy = self._assemble_and_solve_soa_eq(
            dFdu_form, adj_sol, hessian_input, d2Fdu2, bdy)

        r = {}
        r["adj_sol2"] = adj_sol2
        r["adj_sol2_bdy"] = adj_sol2_bdy
        r["form"] = F_form
        r["adj_sol"] = adj_sol
        return r
Beispiel #2
0
    def second_derivative_action(self, dependencies, values, inner_variable, inner_contraction_vector, outer_variable, hermitian, action_vector):

        if isinstance(self.form, ufl.form.Form):
            # Find the dolfin Function corresponding to variable.
            dolfin_inner_variable = values[dependencies.index(inner_variable)].data
            dolfin_outer_variable = values[dependencies.index(outer_variable)].data

            dolfin_dependencies = [dep for dep in _extract_function_coeffs(self.form)]

            dolfin_values = [val.data for val in values]

            current_form = backend.replace(self.form, dict(zip(dolfin_dependencies, dolfin_values)))
            trial = backend.TrialFunction(dolfin_outer_variable.function_space())

            d_rhs = backend.derivative(current_form, dolfin_inner_variable, inner_contraction_vector.data)
            d_rhs = ufl.algorithms.expand_derivatives(d_rhs)
            if len(d_rhs.integrals()) == 0:
                return None

            d_rhs = backend.derivative(d_rhs, dolfin_outer_variable, trial)
            d_rhs = ufl.algorithms.expand_derivatives(d_rhs)

            if len(d_rhs.integrals()) == 0:
                return None

            if hermitian:
                action = backend.action(backend.adjoint(d_rhs), action_vector.data)
            else:
                action = backend.action(d_rhs, action_vector.data)

            return adjlinalg.Vector(action)
        else:
            # RHS is a adjlinalg.Vector. Its derivative is therefore zero.
            raise exceptions.LibadjointErrorNotImplemented("No derivative method for constant RHS.")
Beispiel #3
0
    def second_derivative_action(dependencies, values, inner_variable, inner_contraction_vector, outer_variable, outer_contraction_vector, hermitian, input, coefficient, context):
      dolfin_inner_variable = values[dependencies.index(inner_variable)].data
      dolfin_outer_variable = values[dependencies.index(outer_variable)].data
      dolfin_values = [val.data for val in values]
      expressions.update_expressions(frozen_expressions)
      constant.update_constants(frozen_constants)

      current_form = backend.replace(eq_lhs, dict(zip(diag_coeffs, dolfin_values)))

      deriv = backend.derivative(current_form, dolfin_inner_variable)
      args = ufl.algorithms.extract_arguments(deriv)
      deriv = backend.replace(deriv, {args[1]: inner_contraction_vector.data}) # contract over the middle index

      deriv = backend.derivative(deriv, dolfin_outer_variable)
      args = ufl.algorithms.extract_arguments(deriv)
      deriv = backend.replace(deriv, {args[1]: outer_contraction_vector.data}) # contract over the middle index

      # Assemble the G-matrix now, so that we can apply the Dirichlet BCs to it
      if len(ufl.algorithms.extract_arguments(ufl.algorithms.expand_derivatives(coefficient*deriv))) == 0:
        return adjlinalg.Vector(None)

      G = coefficient * deriv

      if hermitian:
        output = backend.action(backend.adjoint(G), input.data)
      else:
        output = backend.action(G, input.data)

      return adjlinalg.Vector(output)
Beispiel #4
0
    def _assemble_soa_eq_rhs(self, dFdu_form, adj_sol, hessian_input, d2Fdu2):
        # Start piecing together the rhs of the soa equation
        b = hessian_input.copy()
        b_form = d2Fdu2

        for bo in self.get_dependencies():
            c = bo.output
            c_rep = bo.saved_output
            tlm_input = bo.tlm_value

            if (c == self.func and not self.linear) or tlm_input is None:
                continue

            if isinstance(c, compat.MeshType):
                X = backend.SpatialCoordinate(c)
                dFdu_adj = backend.action(backend.adjoint(dFdu_form), adj_sol)
                d2Fdudm = ufl.algorithms.expand_derivatives(
                    backend.derivative(dFdu_adj, X, tlm_input))
                if len(d2Fdudm.integrals()) > 0:
                    b -= compat.assemble_adjoint_value(d2Fdudm)

            elif not isinstance(c, backend.DirichletBC):
                b_form += backend.derivative(dFdu_form, c_rep, tlm_input)

        b_form = ufl.algorithms.expand_derivatives(b_form)
        if len(b_form.integrals()) > 0:
            b_form = backend.adjoint(b_form)
            b -= compat.assemble_adjoint_value(backend.action(b_form, adj_sol))
        return b
    def equation_partial_second_derivative(self, adjointer, adjoint, i,
                                           variable, m_dot):
        form = adjresidual.get_residual(i)
        if form is not None:
            form = -form

            mesh = ufl.algorithms.extract_arguments(
                form)[0].function_space().mesh()
            fn_space = backend.FunctionSpace(mesh, "R", 0)
            dparam = backend.Function(fn_space)
            dparam.vector()[:] = 1.0 * float(self.coeff)
            d2param = backend.Function(fn_space)
            d2param.vector()[:] = 1.0 * float(self.coeff) * m_dot

            diff_form = ufl.algorithms.expand_derivatives(
                backend.derivative(form, get_constant(self.a), dparam))
            if diff_form is None:
                return None

            diff_form = ufl.algorithms.expand_derivatives(
                backend.derivative(diff_form, get_constant(self.a), d2param))
            if diff_form is None:
                return None

            # Let's see if the form actually depends on the parameter m
            if len(diff_form.integrals()) != 0:
                dFdm = backend.assemble(diff_form)  # actually - dF/dm
                assert isinstance(dFdm, backend.GenericVector)

                out = dFdm.inner(adjoint.vector())
                return out
            else:
                return None  # dF/dm is zero, return None
    def functional_partial_second_derivative(self, adjointer, J, timestep,
                                             m_dot):
        form = J.get_form(adjointer, timestep)

        if form is None:
            return None

        for coeff in ufl.algorithms.extract_coefficients(form):
            try:
                mesh = coeff.function_space().mesh()
                fn_space = backend.FunctionSpace(mesh, "R", 0)
                break
            except:
                pass

        dparam = backend.Function(fn_space)
        dparam.vector()[:] = 1.0 * float(self.coeff)

        d = backend.derivative(form, get_constant(self.a), dparam)
        d = ufl.algorithms.expand_derivatives(d)

        d2param = backend.Function(fn_space)
        d2param.vector()[:] = 1.0 * float(self.coeff) * m_dot

        d = backend.derivative(d, get_constant(self.a), d2param)
        d = ufl.algorithms.expand_derivatives(d)

        if len(d.integrals()) != 0:
            return backend.assemble(d)
        else:
            return None
Beispiel #7
0
    def __init__(self, form, control):

        if not isinstance(control.control, backend.Function):
            raise NotImplementedError("Only implemented for Function controls")

        args = ufl.algorithms.extract_arguments(form)
        if len(args) != 0:
            raise ValueError("Must be a rank-zero form, i.e. a functional")

        u = control.control
        self.V = u.function_space()
        # We want to make a copy of the control purely for use
        # in the constraint, so that our writing it isn't
        # bothering anyone else
        self.u = backend_types.Function(self.V)
        self.form = ufl.replace(form, {u: self.u})

        self.trial = backend.TrialFunction(self.V)
        self.dform = backend.derivative(self.form, self.u, self.trial)
        if len(
                ufl.algorithms.extract_arguments(
                    ufl.algorithms.expand_derivatives(self.dform))) == 0:
            raise ValueError("Form must depend on control")

        self.test = backend.TestFunction(self.V)
        self.hess = ufl.algorithms.expand_derivatives(
            backend.derivative(self.dform, self.u, self.test))
        if len(ufl.algorithms.extract_arguments(self.hess)) == 0:
            self.zero_hess = True
        else:
            self.zero_hess = False
Beispiel #8
0
  def equation_partial_second_derivative(self, adjointer, adjoint, i, variable, m_dot):
    form = adjresidual.get_residual(i)
    if form is not None:
      form = -form

      mesh = ufl.algorithms.extract_arguments(form)[0].function_space().mesh()
      fn_space = backend.FunctionSpace(mesh, "R", 0)
      dparam = backend.Function(fn_space)
      dparam.vector()[:] = 1.0 * float(self.coeff)
      d2param = backend.Function(fn_space)
      d2param.vector()[:] = 1.0 * float(self.coeff) * m_dot

      diff_form = ufl.algorithms.expand_derivatives(backend.derivative(form, get_constant(self.a), dparam))
      if diff_form is None:
        return None

      diff_form  = ufl.algorithms.expand_derivatives(backend.derivative(diff_form, get_constant(self.a), d2param))
      if diff_form is None:
        return None

      # Let's see if the form actually depends on the parameter m
      if len(diff_form.integrals()) != 0:
        dFdm = backend.assemble(diff_form) # actually - dF/dm
        assert isinstance(dFdm, backend.GenericVector)

        out = dFdm.inner(adjoint.vector())
        return out
      else:
        return None # dF/dm is zero, return None
Beispiel #9
0
  def functional_partial_second_derivative(self, adjointer, J, timestep, m_dot):
    form = J.get_form(adjointer, timestep)

    if form is None:
      return None

    for coeff in ufl.algorithms.extract_coefficients(form):
      try:
        mesh = coeff.function_space().mesh()
        fn_space = backend.FunctionSpace(mesh, "R", 0)
        break
      except:
        pass

    dparam = backend.Function(fn_space)
    dparam.vector()[:] = 1.0 * float(self.coeff)

    d = backend.derivative(form, get_constant(self.a), dparam)
    d = ufl.algorithms.expand_derivatives(d)

    d2param = backend.Function(fn_space)
    d2param.vector()[:] = 1.0 * float(self.coeff) * m_dot

    d = backend.derivative(d, get_constant(self.a), d2param)
    d = ufl.algorithms.expand_derivatives(d)

    if len(d.integrals()) != 0:
      return backend.assemble(d)
    else:
      return None
Beispiel #10
0
    def evaluate_hessian_component(self,
                                   inputs,
                                   hessian_inputs,
                                   adj_inputs,
                                   block_variable,
                                   idx,
                                   relevant_dependencies,
                                   prepared=None):
        form = prepared
        hessian_input = hessian_inputs[0]
        adj_input = adj_inputs[0]

        c1 = block_variable.output
        c1_rep = block_variable.saved_output

        if isinstance(c1, backend.Function):
            dc = backend.TestFunction(c1.function_space())
        elif isinstance(c1, compat.ExpressionType):
            mesh = form.ufl_domain().ufl_cargo()
            W = c1._ad_function_space(mesh)
            dc = backend.TestFunction(W)
        elif isinstance(c1, backend.Constant):
            mesh = compat.extract_mesh_from_form(form)
            dc = backend.TestFunction(c1._ad_function_space(mesh))
        elif isinstance(c1, compat.MeshType):
            pass
        else:
            return None

        if isinstance(c1, compat.MeshType):
            X = backend.SpatialCoordinate(c1)
            dform = backend.derivative(form, X)
        else:
            dform = backend.derivative(form, c1_rep, dc)
        hessian_outputs = hessian_input * compat.assemble_adjoint_value(dform)

        for other_idx, bv in relevant_dependencies:
            c2_rep = bv.saved_output
            tlm_input = bv.tlm_value

            if tlm_input is None:
                continue

            if isinstance(c2_rep, compat.MeshType):
                X = backend.SpatialCoordinate(c2_rep)
                ddform = backend.derivative(dform, X, tlm_input)
            else:
                ddform = backend.derivative(dform, c2_rep, tlm_input)
            hessian_outputs += adj_input * compat.assemble_adjoint_value(
                ddform)

        if isinstance(c1, compat.ExpressionType):
            return [(hessian_outputs, W)]
        else:
            return hessian_outputs
Beispiel #11
0
    def evaluate_tlm_component(self,
                               inputs,
                               tlm_inputs,
                               block_variable,
                               idx,
                               prepared=None):
        F_form = prepared["form"]
        dFdu = prepared["dFdu"]
        V = self.get_outputs()[idx].output.function_space()

        bcs = []
        dFdm = 0.
        dFdm_shape = 0.
        for block_variable in self.get_dependencies():
            tlm_value = block_variable.tlm_value
            c = block_variable.output
            c_rep = block_variable.saved_output

            if isinstance(c, backend.DirichletBC):
                if tlm_value is None:
                    bcs.append(compat.create_bc(c, homogenize=True))
                else:
                    bcs.append(tlm_value)
                continue
            elif isinstance(c, compat.MeshType):
                X = backend.SpatialCoordinate(c)
                c_rep = X

            if tlm_value is None:
                continue

            if c == self.func and not self.linear:
                continue

            if isinstance(c, compat.MeshType):
                dFdm_shape += compat.assemble_adjoint_value(
                    backend.derivative(-F_form, c_rep, tlm_value))
            else:
                dFdm += backend.derivative(-F_form, c_rep, tlm_value)

        if isinstance(dFdm, float):
            v = dFdu.arguments()[0]
            dFdm = backend.inner(backend.Constant(numpy.zeros(v.ufl_shape)),
                                 v) * backend.dx

        dFdm = compat.assemble_adjoint_value(dFdm) + dFdm_shape
        dudm = backend.Function(V)
        return self._assemble_and_solve_tlm_eq(
            compat.assemble_adjoint_value(dFdu, bcs=bcs), dFdm, dudm, bcs)
Beispiel #12
0
    def derivative_action(self, dependencies, values, variable, contraction_vector, hermitian):

        if contraction_vector.data is None:
            return adjlinalg.Vector(None)

        if isinstance(self.form, ufl.form.Form):
            # Find the dolfin Function corresponding to variable.
            dolfin_variable = values[dependencies.index(variable)].data

            dolfin_dependencies = [dep for dep in _extract_function_coeffs(self.form)]

            dolfin_values = [val.data for val in values]

            current_form = backend.replace(self.form, dict(zip(dolfin_dependencies, dolfin_values)))
            trial = backend.TrialFunction(dolfin_variable.function_space())

            d_rhs = backend.derivative(current_form, dolfin_variable, trial)

            if hermitian:
                action = backend.action(backend.adjoint(d_rhs), contraction_vector.data)
            else:
                action = backend.action(d_rhs, contraction_vector.data)

            return adjlinalg.Vector(action)
        else:
            # RHS is a adjlinalg.Vector. Its derivative is therefore zero.
            return adjlinalg.Vector(None)
Beispiel #13
0
    def prepare_evaluate_adj(self, inputs, adj_inputs, relevant_dependencies):
        fwd_block_variable = self.get_outputs()[0]
        u = fwd_block_variable.output

        dJdu = adj_inputs[0]

        F_form = self._create_F_form()

        dFdu = backend.derivative(F_form, fwd_block_variable.saved_output,
                                  backend.TrialFunction(u.function_space()))
        dFdu_form = backend.adjoint(dFdu)
        dJdu = dJdu.copy()

        compute_bdy = self._should_compute_boundary_adjoint(
            relevant_dependencies)
        adj_sol, adj_sol_bdy = self._assemble_and_solve_adj_eq(
            dFdu_form, dJdu, compute_bdy)
        self.adj_sol = adj_sol
        if self.adj_cb is not None:
            self.adj_cb(adj_sol)
        if self.adj_bdy_cb is not None and compute_bdy:
            self.adj_bdy_cb(adj_sol_bdy)

        r = {}
        r["form"] = F_form
        r["adj_sol"] = adj_sol
        r["adj_sol_bdy"] = adj_sol_bdy
        return r
Beispiel #14
0
    def __init__(self, form, F, u, bcs, mass, solver_parameters, J):
        '''form is M.u - F(u). F is the nonlinear equation, F(u) := 0.'''
        RHS.__init__(self, form)
        self.F = F
        self.u = u
        self.bcs = bcs
        self.mass = mass
        self.solver_parameters = solver_parameters
        self.J = J or backend.derivative(F, u)

        # We want to mark that the RHS term /also/ depends on
        # the previous value of u, as that's what we need to initialise
        # the nonlinear solver.
        var = adjglobals.adj_variables[self.u]
        self.ic_var = None

        if backend.parameters["adjoint"]["fussy_replay"]:
            can_depend = True
            try:
                prev_var = find_previous_variable(var)
            except:
                can_depend = False

            if can_depend:
                self.ic_var = prev_var
                self.deps += [self.ic_var]
                self.coeffs += [u]

            else:
                self.ic_copy = backend.Function(u)
                self.ic_var = None
Beispiel #15
0
    def derivative_action(self, dependencies, values, variable,
                          contraction_vector, hermitian):

        if contraction_vector.data is None:
            return adjlinalg.Vector(None)

        if isinstance(self.form, ufl.form.Form):
            # Find the dolfin Function corresponding to variable.
            dolfin_variable = values[dependencies.index(variable)].data

            dolfin_dependencies = [
                dep for dep in _extract_function_coeffs(self.form)
            ]

            dolfin_values = [val.data for val in values]

            current_form = backend.replace(
                self.form, dict(zip(dolfin_dependencies, dolfin_values)))
            trial = backend.TrialFunction(dolfin_variable.function_space())

            d_rhs = backend.derivative(current_form, dolfin_variable, trial)

            if hermitian:
                action = backend.action(backend.adjoint(d_rhs),
                                        contraction_vector.data)
            else:
                action = backend.action(d_rhs, contraction_vector.data)

            return adjlinalg.Vector(action)
        else:
            # RHS is a adjlinalg.Vector. Its derivative is therefore zero.
            return adjlinalg.Vector(None)
Beispiel #16
0
    def derivative_assembly(self, dependencies, values, variable, hermitian):
        replace_map = {}

        for i in range(len(self.deps)):
            if self.deps[i] == self.ic_var: continue
            j = dependencies.index(self.deps[i])
            replace_map[self.coeffs[i]] = values[j].data

        diff_var = values[dependencies.index(variable)].data

        current_form = backend.replace(self.form, replace_map)
        deriv = backend.derivative(current_form, diff_var)

        if hermitian:
            deriv = backend.adjoint(deriv)
            bcs = [
                utils.homogenize(bc)
                for bc in self.bcs if isinstance(bc, backend.DirichletBC)
            ] + [
                bc
                for bc in self.bcs if not isinstance(bc, backend.DirichletBC)
            ]
        else:
            bcs = self.bcs

        return adjlinalg.Matrix(deriv, bcs=bcs)
Beispiel #17
0
    def __init__(self, form, F, u, bcs, mass, solver_parameters, J):
        '''form is M.u - F(u). F is the nonlinear equation, F(u) := 0.'''
        RHS.__init__(self, form)
        self.F = F
        self.u = u
        self.bcs = bcs
        self.mass = mass
        self.solver_parameters = solver_parameters
        self.J = J or backend.derivative(F, u)

        # We want to mark that the RHS term /also/ depends on
        # the previous value of u, as that's what we need to initialise
        # the nonlinear solver.
        var = adjglobals.adj_variables[self.u]
        self.ic_var = None

        if backend.parameters["adjoint"]["fussy_replay"]:
            can_depend = True
            try:
                prev_var = find_previous_variable(var)
            except:
                can_depend = False

            if can_depend:
                self.ic_var = prev_var
                self.deps += [self.ic_var]
                self.coeffs += [u]

            else:
                self.ic_copy = backend.Function(u)
                self.ic_var = None
Beispiel #18
0
    def equation_partial_derivative(self, adjointer, adjoint, i, variable):
        form = adjresidual.get_residual(i)

        if form is None:
            return None
        else:
            form = -form

        fn_space = ufl.algorithms.extract_arguments(form)[0].function_space()
        dparam = backend.Function(
            backend.FunctionSpace(fn_space.mesh(), "R", 0))
        dparam.vector()[:] = 1.0

        dJdv = numpy.zeros(len(self.v))
        for (i, a) in enumerate(self.v):
            diff_form = ufl.algorithms.expand_derivatives(
                backend.derivative(form, a, dparam))

            dFdm = backend.assemble(diff_form)  # actually - dF/dm
            assert isinstance(dFdm, backend.GenericVector)

            out = dFdm.inner(adjoint.vector())
            dJdv[i] = out

        return dJdv
    def second_derivative(self, adjointer, variable, dependencies, values, contraction):

        if contraction.data is None:
            return adjlinalg.Vector(None)

        functional_value = None
        for timestep in self._derivative_timesteps(adjointer, variable):
            functional_value = _add(functional_value,
                                    self._substitute_form(adjointer, timestep, dependencies, values))

        d = backend.derivative(functional_value, values[dependencies.index(variable)].data)
        d = ufl.algorithms.expand_derivatives(d)
        d = backend.derivative(d, values[dependencies.index(variable)].data, contraction.data)
        if len(d.integrals()) == 0:
            raise SystemExit, "This isn't supposed to happen -- your functional is supposed to depend on %s" % variable
        return adjlinalg.Vector(d)
Beispiel #20
0
    def functional_partial_derivative(self, adjointer, J, timestep):
        form = J.get_form(adjointer, timestep)

        if form is None:
            return None

        # OK. Now that we have the form for the functional at this timestep, let's differentiate it with respect to
        # my dear Constant, and be done.
        for coeff in ufl.algorithms.extract_coefficients(form):
            try:
                mesh = coeff.function_space().mesh()
                fn_space = backend.FunctionSpace(mesh, "R", 0)
                break
            except:
                pass

        dparam = backend.Function(fn_space)
        dparam.vector()[:] = 1.0 * float(self.coeff)

        d = backend.derivative(form, get_constant(self.a), dparam)
        d = ufl.algorithms.expand_derivatives(d)

        # Add the derivatives of Expressions wrt to the Constant
        d = self.expression_derivative(form, d)

        if len(d.integrals()) != 0:
            return backend.assemble(d)
        else:
            return None
Beispiel #21
0
    def equation_partial_derivative(self, adjointer, adjoint, i, variable):
        form = adjresidual.get_residual(i)
        if form is not None:
            form = -form

            mesh = ufl.algorithms.extract_arguments(
                form)[0].function_space().mesh()
            fn_space = backend.FunctionSpace(mesh, "R", 0)
            dparam = backend.Function(fn_space)
            dparam.vector()[:] = 1.0 * float(self.coeff)

            diff_form = ufl.algorithms.expand_derivatives(
                backend.derivative(form, get_constant(self.a), dparam))

            # Add the derivatives of Expressions wrt to the Constant
            diff_form = self.expression_derivative(form, diff_form)

            # Let's see if the form actually depends on the parameter m
            if len(diff_form.integrals()) != 0:
                dFdm = backend.assemble(diff_form)  # actually - dF/dm
                out = adjoint.vector().inner(dFdm)
            else:
                out = None  # dF/dm is zero, return None

            return out
Beispiel #22
0
  def functional_partial_derivative(self, adjointer, J, timestep):
    form = J.get_form(adjointer, timestep)

    if form is None:
      return None

    # OK. Now that we have the form for the functional at this timestep, let's differentiate it with respect to
    # my dear Constant, and be done.
    for coeff in ufl.algorithms.extract_coefficients(form):
      try:
        mesh = coeff.function_space().mesh()
        fn_space = backend.FunctionSpace(mesh, "R", 0)
        break
      except:
        pass

    dparam = backend.Function(fn_space)
    dparam.vector()[:] = 1.0 * float(self.coeff)

    d = backend.derivative(form, get_constant(self.a), dparam)
    d = ufl.algorithms.expand_derivatives(d)

    # Add the derivatives of Expressions wrt to the Constant
    d = self.expression_derivative(form, d)

    if len(d.integrals()) != 0:
      return backend.assemble(d)
    else:
      return None
Beispiel #23
0
    def evaluate_adj_component(self,
                               inputs,
                               adj_inputs,
                               block_variable,
                               idx,
                               prepared=None):
        if not self.linear and self.func == block_variable.output:
            # We are not able to calculate derivatives wrt initial guess.
            return None
        F_form = prepared["form"]
        adj_sol = prepared["adj_sol"]
        adj_sol_bdy = prepared["adj_sol_bdy"]
        c = block_variable.output
        c_rep = block_variable.saved_output

        if isinstance(c, backend.Function):
            trial_function = backend.TrialFunction(c.function_space())
        elif isinstance(c, backend.Constant):
            mesh = compat.extract_mesh_from_form(F_form)
            trial_function = backend.TrialFunction(c._ad_function_space(mesh))
        elif isinstance(c, compat.ExpressionType):
            mesh = F_form.ufl_domain().ufl_cargo()
            c_fs = c._ad_function_space(mesh)
            trial_function = backend.TrialFunction(c_fs)
        elif isinstance(c, backend.DirichletBC):
            tmp_bc = compat.create_bc(c,
                                      value=extract_subfunction(
                                          adj_sol_bdy, c.function_space()))
            return [tmp_bc]
        elif isinstance(c, compat.MeshType):
            # Using CoordianteDerivative requires us to do action before
            # differentiating, might change in the future.
            F_form_tmp = backend.action(F_form, adj_sol)
            X = backend.SpatialCoordinate(c_rep)
            dFdm = backend.derivative(-F_form_tmp, X)
            dFdm = compat.assemble_adjoint_value(dFdm, **self.assemble_kwargs)
            return dFdm

        dFdm = -backend.derivative(F_form, c_rep, trial_function)
        dFdm = backend.adjoint(dFdm)
        dFdm = dFdm * adj_sol
        dFdm = compat.assemble_adjoint_value(dFdm, **self.assemble_kwargs)
        if isinstance(c, compat.ExpressionType):
            return [[dFdm, c_fs]]
        else:
            return dFdm
Beispiel #24
0
    def second_derivative_action(self, dependencies, values, inner_variable,
                                 inner_contraction_vector, outer_variable,
                                 hermitian, action_vector):

        if isinstance(self.form, ufl.form.Form):
            # Find the dolfin Function corresponding to variable.
            dolfin_inner_variable = values[dependencies.index(
                inner_variable)].data
            dolfin_outer_variable = values[dependencies.index(
                outer_variable)].data

            dolfin_dependencies = [
                dep for dep in _extract_function_coeffs(self.form)
            ]

            dolfin_values = [val.data for val in values]

            current_form = backend.replace(
                self.form, dict(zip(dolfin_dependencies, dolfin_values)))
            trial = backend.TrialFunction(
                dolfin_outer_variable.function_space())

            d_rhs = backend.derivative(current_form, dolfin_inner_variable,
                                       inner_contraction_vector.data)
            d_rhs = ufl.algorithms.expand_derivatives(d_rhs)
            if len(d_rhs.integrals()) == 0:
                return None

            d_rhs = backend.derivative(d_rhs, dolfin_outer_variable, trial)
            d_rhs = ufl.algorithms.expand_derivatives(d_rhs)

            if len(d_rhs.integrals()) == 0:
                return None

            if hermitian:
                action = backend.action(backend.adjoint(d_rhs),
                                        action_vector.data)
            else:
                action = backend.action(d_rhs, action_vector.data)

            return adjlinalg.Vector(action)
        else:
            # RHS is a adjlinalg.Vector. Its derivative is therefore zero.
            raise libadjoint.exceptions.LibadjointErrorNotImplemented(
                "No derivative method for constant RHS.")
  def derivative_action(self, variable, contraction_vector, hermitian, input, coefficient):
    deriv = backend.derivative(self.current_form, variable)
    args = ufl.algorithms.extract_arguments(deriv)
    deriv = backend.replace(deriv, {args[1]: contraction_vector})

    if hermitian:
      deriv = backend.adjoint(deriv)

    action = coefficient * backend.action(deriv, input)

    return action
Beispiel #26
0
    def prepare_evaluate_tlm(self, inputs, tlm_inputs, relevant_outputs):
        fwd_block_variable = self.get_outputs()[0]
        u = fwd_block_variable.output

        F_form = self._create_F_form()

        # Obtain dFdu.
        dFdu = backend.derivative(F_form, fwd_block_variable.saved_output,
                                  backend.TrialFunction(u.function_space()))

        return {"form": F_form, "dFdu": dFdu}
    def derivative_action(self, variable, contraction_vector, hermitian, input,
                          coefficient):
        deriv = backend.derivative(self.current_form, variable)
        args = ufl.algorithms.extract_arguments(deriv)
        deriv = backend.replace(deriv, {args[1]: contraction_vector})

        if hermitian:
            deriv = backend.adjoint(deriv)

        action = coefficient * backend.action(deriv, input)

        return action
Beispiel #28
0
    def second_derivative(self, adjointer, variable, dependencies, values,
                          contraction):

        if contraction.data is None:
            return adjlinalg.Vector(None)

        functional_value = None
        for timestep in self._derivative_timesteps(adjointer, variable):
            functional_value = _add(
                functional_value,
                self._substitute_form(adjointer, timestep, dependencies,
                                      values))

        d = backend.derivative(functional_value,
                               values[dependencies.index(variable)].data)
        d = ufl.algorithms.expand_derivatives(d)
        d = backend.derivative(d, values[dependencies.index(variable)].data,
                               contraction.data)
        if len(d.integrals()) == 0:
            raise SystemExit(
                "This isn't supposed to happen -- your functional is supposed to depend on %s"
                % variable)
        return adjlinalg.Vector(d)
Beispiel #29
0
  def __call__(self, adjointer, i, dependencies, values, variable):
    form = adjresidual.get_residual(i)
    if form is not None:
      form = -form

      fn_space = ufl.algorithms.extract_arguments(form)[0].function_space()
      dparam = backend.Function(backend.FunctionSpace(fn_space.mesh(), "R", 0))
      dparam.vector()[:] = 1.0 * float(self.coeff)

      diff_form = ufl.algorithms.expand_derivatives(backend.derivative(form, get_constant(self.a), dparam))

      return adjlinalg.Vector(diff_form)
    else:
      return None
Beispiel #30
0
    def evaluate_tlm_component(self,
                               inputs,
                               tlm_inputs,
                               block_variable,
                               idx,
                               prepared=None):
        form = prepared
        dform = 0.
        dform_shape = 0.
        for bv in self.get_dependencies():
            c_rep = bv.saved_output
            tlm_value = bv.tlm_value

            if tlm_value is None:
                continue
            if isinstance(c_rep, compat.MeshType):
                X = backend.SpatialCoordinate(c_rep)
                dform_shape += compat.assemble_adjoint_value(
                    backend.derivative(form, X, tlm_value))
            else:
                dform += backend.derivative(form, c_rep, tlm_value)
        if not isinstance(dform, float):
            dform = compat.assemble_adjoint_value(dform)
        return dform + dform_shape
Beispiel #31
0
    def evaluate_adj_component(self,
                               inputs,
                               adj_inputs,
                               block_variable,
                               idx,
                               prepared=None):
        form = prepared
        adj_input = adj_inputs[0]
        c = block_variable.output
        c_rep = block_variable.saved_output

        if isinstance(c, compat.ExpressionType):
            # Create a FunctionSpace from self.form and Expression.
            # And then make a TestFunction from this space.
            mesh = self.form.ufl_domain().ufl_cargo()
            V = c._ad_function_space(mesh)
            dc = backend.TestFunction(V)

            dform = backend.derivative(form, c_rep, dc)
            output = compat.assemble_adjoint_value(dform)
            return [[adj_input * output, V]]
        elif isinstance(c, compat.MeshType):
            X = backend.SpatialCoordinate(c_rep)
            dform = backend.derivative(form, X)
            output = compat.assemble_adjoint_value(dform)
            return adj_input * output

        if isinstance(c, backend.Function):
            dc = backend.TestFunction(c.function_space())
        elif isinstance(c, backend.Constant):
            mesh = compat.extract_mesh_from_form(self.form)
            dc = backend.TestFunction(c._ad_function_space(mesh))

        dform = backend.derivative(form, c_rep, dc)
        output = compat.assemble_adjoint_value(dform)
        return adj_input * output
Beispiel #32
0
  def expression_derivative(self, form, diff_form):
      """ Applies the chain rule on diff_form to add derivatives of Expressions
          with respect to the control. """

      coeffs = ufl.algorithms.extract_coefficients(form)

      # Take the derivative of Expressions with respect to Constants only
      # if the derivative is provided explicitly by the user
      expr_deriv_coeffs = []
      for coeff in coeffs:

          # Check if the coefficient is an expression with user-defined
          # derivatives
          if not hasattr(coeff, "deval"):
              continue

          if not hasattr(coeff, "dependencies"):
              raise ValueError, "An expression with deval() must also \
                                 implement the dependencies() function."

          if not hasattr(coeff, "copy"):
              raise ValueError, "An expression with deval() must also \
                                 implement the copy() function."

          # Check that that expression depends on self.a
          elif self.a not in coeff.dependencies():
              continue

          else:
              expr_deriv_coeffs.append(coeff)


      # Ok, so diff_form has the expression "coeff" which depends on self.a
      # For the following computation we temporarly change this expression
      # such that it returns the derivative wrt to self.a instead of
      # plain evaluation.
      # Now apply the chain rule to expand the diff_form through these
      # expressions
      for c in expr_deriv_coeffs:

          dc = c.copy()
          eval_deriv_a = lambda expr, value, x: expr.deval(value, x, self.a)
          dc.eval = types.MethodType(eval_deriv_a, dc)

          diff_form += ufl.algorithms.expand_derivatives(
              backend.derivative(form, c, dc))

      return diff_form
    def derivative(self, adjointer, variable, dependencies, values):

        functional_value = None
        for timestep in self._derivative_timesteps(adjointer, variable):
            functional_value = _add(functional_value,
                                    self._substitute_form(adjointer, timestep, dependencies, values))

        if functional_value is None:
            backend.info_red("Your functional is supposed to depend on %s, but does not?" % variable)
            raise libadjoint.exceptions.LibadjointErrorInvalidInputs

        d = backend.derivative(functional_value, values[dependencies.index(variable)].data)
        d = ufl.algorithms.expand_derivatives(d)

        if len(d.integrals()) == 0:
            raise SystemExit, "This isn't supposed to happen -- your functional is supposed to depend on %s" % variable
        return adjlinalg.Vector(d)
Beispiel #34
0
    def __call__(self, adjointer, i, dependencies, values, variable):
        form = adjresidual.get_residual(i)
        if form is not None:
            form = -form

            fn_space = ufl.algorithms.extract_arguments(
                form)[0].function_space()
            dparam = backend.Function(
                backend.FunctionSpace(fn_space.mesh(), "R", 0))
            dparam.vector()[:] = 1.0 * float(self.coeff)

            diff_form = ufl.algorithms.expand_derivatives(
                backend.derivative(form, get_constant(self.a), dparam))

            return adjlinalg.Vector(diff_form)
        else:
            return None
Beispiel #35
0
    def derivative_assembly(self, dependencies, values, variable, hermitian):
        replace_map = {}

        for i in range(len(self.deps)):
            if self.deps[i] == self.ic_var: continue
            j = dependencies.index(self.deps[i])
            replace_map[self.coeffs[i]] = values[j].data

        diff_var = values[dependencies.index(variable)].data

        current_form = backend.replace(self.form, replace_map)
        deriv = backend.derivative(current_form, diff_var)

        if hermitian:
            deriv = backend.adjoint(deriv)
            bcs = [utils.homogenize(bc) for bc in self.bcs if isinstance(bc, backend.DirichletBC)] + [bc for bc in self.bcs if not isinstance(bc, backend.DirichletBC)]
        else:
            bcs = self.bcs

        return adjlinalg.Matrix(deriv, bcs=bcs)
Beispiel #36
0
    def expression_derivative(self, form, diff_form):
        """ Applies the chain rule on diff_form to add derivatives of Expressions
            with respect to the control. """

        coeffs = ufl.algorithms.extract_coefficients(form)

        # Take the derivative of Expressions with respect to Constants only
        # if the derivative is provided explicitly by the user
        expr_deriv_coeffs = []
        for coeff in coeffs:

            # Check if the coefficient is an expression with user-defined
            # derivatives

            if not hasattr(coeff, "dependencies"):
                continue
            if not hasattr(coeff, "user_defined_derivatives"):
                raise ValueError, "An expression with dependencies must also \
provide the user_defined_derivatives \
dictionary."

            # Check that that expression depends on self.a
            elif self.a not in coeff.dependencies:
                continue

            else:
                expr_deriv_coeffs.append(coeff)


        # Ok, so diff_form has the expression "coeff" which depends on self.a
        # For the following computation we temporarly change this expression
        # such that it returns the derivative wrt to self.a instead of
        # plain evaluation.
        # Now apply the chain rule to expand the diff_form through these
        # expressions
        for c in expr_deriv_coeffs:

            diff_form += ufl.algorithms.expand_derivatives(
                backend.derivative(form, c, c.user_defined_derivatives[self.a]))

        return diff_form
Beispiel #37
0
    def expression_derivative(self, form, diff_form):
        """ Applies the chain rule on diff_form to add derivatives of Expressions
            with respect to the control. """

        coeffs = ufl.algorithms.extract_coefficients(form)

        # Take the derivative of Expressions with respect to Constants only
        # if the derivative is provided explicitly by the user
        expr_deriv_coeffs = []
        for coeff in coeffs:

            # Check if the coefficient is an expression with user-defined
            # derivatives

            if not hasattr(coeff, "dependencies"):
                continue
            if not hasattr(coeff, "user_defined_derivatives"):
                raise ValueError("An expression with dependencies must also \
provide the user_defined_derivatives \
dictionary.")

            # Check that that expression depends on self.a
            elif self.a not in coeff.dependencies:
                continue

            else:
                expr_deriv_coeffs.append(coeff)

        # Ok, so diff_form has the expression "coeff" which depends on self.a
        # For the following computation we temporarly change this expression
        # such that it returns the derivative wrt to self.a instead of
        # plain evaluation.
        # Now apply the chain rule to expand the diff_form through these
        # expressions
        for c in expr_deriv_coeffs:

            diff_form += ufl.algorithms.expand_derivatives(
                backend.derivative(form, c,
                                   c.user_defined_derivatives[self.a]))

        return diff_form
Beispiel #38
0
  def equation_partial_derivative(self, adjointer, adjoint, i, variable):
    form = adjresidual.get_residual(i)

    if form is None:
      return None
    else:
      form = -form

    fn_space = ufl.algorithms.extract_arguments(form)[0].function_space()
    dparam = backend.Function(backend.FunctionSpace(fn_space.mesh(), "R", 0))
    dparam.vector()[:] = 1.0

    dJdv = numpy.zeros(len(self.v))
    for (i, a) in enumerate(self.v):
      diff_form = ufl.algorithms.expand_derivatives(backend.derivative(form, a, dparam))

      dFdm = backend.assemble(diff_form) # actually - dF/dm
      assert isinstance(dFdm, backend.GenericVector)

      out = dFdm.inner(adjoint.vector())
      dJdv[i] = out

    return dJdv
Beispiel #39
0
  def __call__(self, adjointer, i, dependencies, values, variable):
    diff_form = None
    assert self.dv is not None, "Need a perturbation direction to use in the TLM."

    form = adjresidual.get_residual(i)

    if form is None:
      return None
    else:
      form = -form

    fn_space = ufl.algorithms.extract_arguments(form)[0].function_space()
    dparam = backend.Function(backend.FunctionSpace(fn_space.mesh(), "R", 0))
    dparam.vector()[:] = 1.0

    for (a, da) in zip(self.v, self.dv):
      out_form = da * backend.derivative(form, a, dparam)
      if diff_form is None:
        diff_form = out_form
      else:
        diff_form += out_form

    return adjlinalg.Vector(diff_form)
Beispiel #40
0
    def derivative(self, adjointer, variable, dependencies, values):

        functional_value = None
        for timestep in self._derivative_timesteps(adjointer, variable):
            functional_value = _add(
                functional_value,
                self._substitute_form(adjointer, timestep, dependencies,
                                      values))

        if functional_value is None:
            backend.info_red(
                "Your functional is supposed to depend on %s, but does not?" %
                variable)
            raise libadjoint.exceptions.LibadjointErrorInvalidInputs

        d = backend.derivative(functional_value,
                               values[dependencies.index(variable)].data)
        d = ufl.algorithms.expand_derivatives(d)

        if len(d.integrals()) == 0:
            raise SystemExit(
                "This isn't supposed to happen -- your functional is supposed to depend on %s"
                % variable)
        return adjlinalg.Vector(d)
Beispiel #41
0
    def __call__(self, adjointer, i, dependencies, values, variable):
        diff_form = None
        assert self.dv is not None, "Need a perturbation direction to use in the TLM."

        form = adjresidual.get_residual(i)

        if form is None:
            return None
        else:
            form = -form

        fn_space = ufl.algorithms.extract_arguments(form)[0].function_space()
        dparam = backend.Function(
            backend.FunctionSpace(fn_space.mesh(), "R", 0))
        dparam.vector()[:] = 1.0

        for (a, da) in zip(self.v, self.dv):
            out_form = da * backend.derivative(form, a, dparam)
            if diff_form is None:
                diff_form = out_form
            else:
                diff_form += out_form

        return adjlinalg.Vector(diff_form)
Beispiel #42
0
    def evaluate_hessian_component(self,
                                   inputs,
                                   hessian_inputs,
                                   adj_inputs,
                                   block_variable,
                                   idx,
                                   relevant_dependencies,
                                   prepared=None):
        c = block_variable.output
        if c == self.func and not self.linear:
            return None

        adj_sol2 = prepared["adj_sol2"]
        adj_sol2_bdy = prepared["adj_sol2_bdy"]
        F_form = prepared["form"]
        adj_sol = prepared["adj_sol"]
        fwd_block_variable = self.get_outputs()[0]
        tlm_output = fwd_block_variable.tlm_value

        c_rep = block_variable.saved_output

        # If m = DirichletBC then d^2F(u,m)/dm^2 = 0 and d^2F(u,m)/dudm = 0,
        # so we only have the term dF(u,m)/dm * adj_sol2
        if isinstance(c, backend.DirichletBC):
            tmp_bc = compat.create_bc(c,
                                      value=extract_subfunction(
                                          adj_sol2_bdy, c.function_space()))
            return [tmp_bc]

        if isinstance(c_rep, backend.Constant):
            mesh = compat.extract_mesh_from_form(F_form)
            W = c._ad_function_space(mesh)
        elif isinstance(c, compat.ExpressionType):
            mesh = F_form.ufl_domain().ufl_cargo()
            W = c._ad_function_space(mesh)
        elif isinstance(c, compat.MeshType):
            X = backend.SpatialCoordinate(c)
            element = X.ufl_domain().ufl_coordinate_element()
            W = backend.FunctionSpace(c, element)
        else:
            W = c.function_space()

        dc = backend.TestFunction(W)
        form_adj = backend.action(F_form, adj_sol)
        form_adj2 = backend.action(F_form, adj_sol2)
        if isinstance(c, compat.MeshType):
            dFdm_adj = backend.derivative(form_adj, X, dc)
            dFdm_adj2 = backend.derivative(form_adj2, X, dc)
        else:
            dFdm_adj = backend.derivative(form_adj, c_rep, dc)
            dFdm_adj2 = backend.derivative(form_adj2, c_rep, dc)

        # TODO: Old comment claims this might break on split. Confirm if true or not.
        d2Fdudm = ufl.algorithms.expand_derivatives(
            backend.derivative(dFdm_adj, fwd_block_variable.saved_output,
                               tlm_output))

        hessian_output = 0

        # We need to add terms from every other dependency
        # i.e. the terms d^2F/dm_1dm_2
        for _, bv in relevant_dependencies:
            c2 = bv.output
            c2_rep = bv.saved_output

            if isinstance(c2, backend.DirichletBC):
                continue

            tlm_input = bv.tlm_value
            if tlm_input is None:
                continue

            if c2 == self.func and not self.linear:
                continue

            # TODO: If tlm_input is a Sum, this crashes in some instances?
            if isinstance(c2_rep, compat.MeshType):
                X = backend.SpatialCoordinate(c2_rep)
                d2Fdm2 = ufl.algorithms.expand_derivatives(
                    backend.derivative(dFdm_adj, X, tlm_input))
            else:
                d2Fdm2 = ufl.algorithms.expand_derivatives(
                    backend.derivative(dFdm_adj, c2_rep, tlm_input))
            if d2Fdm2.empty():
                continue

            hessian_output -= compat.assemble_adjoint_value(d2Fdm2)

        if not d2Fdudm.empty():
            # FIXME: This can be empty in the multimesh case, ask sebastian
            hessian_output -= compat.assemble_adjoint_value(d2Fdudm)
        hessian_output -= compat.assemble_adjoint_value(dFdm_adj2)

        if isinstance(c, compat.ExpressionType):
            return [(hessian_output, W)]
        else:
            return hessian_output