Esempio n. 1
0
    def __call__(self, dependencies, values):
        assert isinstance(self.form, ufl.form.Form)

        ic = self.u.function_space() # by default, initialise with a blank function in the solution FunctionSpace

        if hasattr(self, "ic_copy"):
            ic = self.ic_copy

        replace_map = {}

        for i in range(len(self.deps)):
            if self.deps[i] in dependencies:
                j = dependencies.index(self.deps[i])
                if self.deps[i] == self.ic_var:
                    ic = values[j].data # ahah, we have found an initial condition!
                else:
                    replace_map[self.coeffs[i]] = values[j].data

        current_F    = backend.replace(self.F, replace_map)
        current_J    = backend.replace(self.J, replace_map)
        u = backend.Function(ic)
        current_F    = backend.replace(current_F, {self.u: u})
        current_J    = backend.replace(current_J, {self.u: u})

        vec = adjlinalg.Vector(None)
        vec.nonlinear_form = current_F
        vec.nonlinear_u = u
        vec.nonlinear_bcs = self.bcs
        vec.nonlinear_J = current_J

        return vec
Esempio n. 2
0
        def derivative_outer_action(
            dependencies, values, variable, contraction_vector, hermitian, input, coefficient, context
        ):
            dolfin_variable = values[dependencies.index(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_variable)
            args = ufl.algorithms.extract_arguments(deriv)
            deriv = backend.replace(deriv, {args[2]: contraction_vector.data})  # contract over the outer 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)
Esempio n. 3
0
    def __call__(self, dependencies, values):
        assert isinstance(self.form, ufl.form.Form)

        if hasattr(self, "ic_copy"):
            ic = self.ic_copy
        else:
            # by default, initialise with a blank function in the solution FunctionSpace
            V = self.u.function_space()
            ic = backend.Function(V)

        replace_map = {}

        for i in range(len(self.deps)):
            if self.deps[i] in dependencies:
                j = dependencies.index(self.deps[i])
                if self.deps[i] == self.ic_var:
                    ic = values[
                        j].data  # ahah, we have found an initial condition!
                else:
                    replace_map[self.coeffs[i]] = values[j].data

        current_F = backend.replace(self.F, replace_map)
        current_J = backend.replace(self.J, replace_map)
        u = ic.copy(deepcopy=True)
        current_F = backend.replace(current_F, {self.u: u})
        current_J = backend.replace(current_J, {self.u: u})

        vec = adjlinalg.Vector(None)
        vec.nonlinear_form = current_F
        vec.nonlinear_u = u
        vec.nonlinear_bcs = self.bcs
        vec.nonlinear_J = current_J

        return vec
Esempio n. 4
0
    def basic_solve(self, var, b):
        if isinstance(self.data, IdentityMatrix):
            x=b.duplicate()
            x.axpy(1.0, b)
            if isinstance(x.data, ufl.Form):
                x = Vector(backend.Function(x.fn_space, backend.assemble(x.data)))
        else:
            if var.type in ['ADJ_TLM', 'ADJ_ADJOINT', 'ADJ_SOA']:
                dirichlet_bcs = [utils.homogenize(bc) for bc in self.bcs if isinstance(bc, backend.DirichletBC)]
                other_bcs  = [bc for bc in self.bcs if not isinstance(bc, backend.DirichletBC)]
                bcs = dirichlet_bcs + other_bcs
            else:
                bcs = self.bcs

            test = self.test_function()

            #FIXME: This is a hack, the test and trial function should carry
            # the MultiMeshFunctionSpace as an attribute
            if hasattr(test, '_V_multi'):
                x = Vector(backend.MultiMeshFunction(test._V_multi))
            else:
                x = Vector(backend.Function(test.function_space()))

            #print "b.data is a %s in the solution of %s" % (b.data.__class__, var)
            if b.data is None and not hasattr(b, 'nonlinear_form'):
                # This means we didn't get any contribution on the RHS of the adjoint system. This could be that the
                # simulation ran further ahead than when the functional was evaluated, or it could be that the
                # functional is set up incorrectly.
                backend.warning("Warning: got zero RHS for the solve associated with variable %s" % var)
            elif isinstance(b.data, backend.Function):

                assembled_lhs = self.assemble_data()
                [bc.apply(assembled_lhs) for bc in bcs]
                assembled_rhs = compatibility.assembled_rhs(b)
                [bc.apply(assembled_rhs) for bc in bcs]

                wrap_solve(assembled_lhs, x.data, assembled_rhs, self.solver_parameters)
            else:
                if hasattr(b, 'nonlinear_form'): # was a nonlinear solve
                    x = compatibility.assign_function_to_vector(x, b.nonlinear_u, function_space = test.function_space())
                    F = backend.replace(b.nonlinear_form, {b.nonlinear_u: x.data})
                    J = backend.replace(b.nonlinear_J, {b.nonlinear_u: x.data})
                    try:
                        compatibility.solve(F == 0, x.data, b.nonlinear_bcs, J=J, solver_parameters=self.solver_parameters)
                    except RuntimeError as rte:
                        x.data.vector()[:] = float("nan")

                else:
                    assembled_lhs = self.assemble_data()
                    [bc.apply(assembled_lhs) for bc in bcs]
                    assembled_rhs = wrap_assemble(b.data, test)
                    [bc.apply(assembled_rhs) for bc in bcs]

                    wrap_solve(assembled_lhs, x.data, assembled_rhs, self.solver_parameters)

        return x
Esempio n. 5
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)
Esempio n. 6
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)
Esempio n. 7
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)
Esempio n. 8
0
def get_residual(i):
    from .adjrhs import adj_get_forward_equation
    (fwd_var, lhs, rhs) = adj_get_forward_equation(i)

    if isinstance(lhs, adjlinalg.IdentityMatrix):
        return None

    fn_space = ufl.algorithms.extract_arguments(lhs)[0].function_space()
    x = backend.Function(fn_space)

    if rhs == 0:
        form = lhs
        x = fwd_var.nonlinear_u
    else:
        form = backend.action(lhs, x) - rhs

    try:
        y = adjglobals.adjointer.get_variable_value(fwd_var).data
    except libadjoint.exceptions.LibadjointErrorNeedValue:
        info_red(
            "Warning: recomputing forward solution; please report this script on launchpad"
        )
        y = adjglobals.adjointer.get_forward_solution(i)[1].data

    form = backend.replace(form, {x: y})

    return form
Esempio n. 9
0
def get_residual(i):
    from adjrhs import adj_get_forward_equation
    (fwd_var, lhs, rhs) = adj_get_forward_equation(i)

    if isinstance(lhs, adjlinalg.IdentityMatrix):
        return None

    fn_space = ufl.algorithms.extract_arguments(lhs)[0].function_space()
    x = backend.Function(fn_space)

    if rhs == 0:
        form = lhs
        x = fwd_var.nonlinear_u
    else:
        form = backend.action(lhs, x) - rhs

    try:
        y = adjglobals.adjointer.get_variable_value(fwd_var).data
    except libadjoint.exceptions.LibadjointErrorNeedValue:
        info_red("Warning: recomputing forward solution; please report this script on launchpad")
        y = adjglobals.adjointer.get_forward_solution(i)[1].data

    form = backend.replace(form, {x: y})

    return form
Esempio n. 10
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.")
Esempio n. 11
0
  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
Esempio n. 12
0
    def diag_assembly_cb(dependencies, values, hermitian, coefficient, context):
        """This callback must conform to the libadjoint Python block assembly
        interface. It returns either the form or its transpose, depending on
        the value of the logical hermitian."""

        assert coefficient == 1

        value_coeffs = [v.data for v in values]
        expressions.update_expressions(frozen_expressions)
        constant.update_constants(frozen_constants)
        eq_l = backend.replace(eq_lhs, dict(zip(diag_coeffs, value_coeffs)))

        kwargs = {"cache": eq_l in caching.assembled_fwd_forms}  # should we cache our matrices on the way backwards?

        if hermitian:
            # Homogenise the adjoint boundary conditions. This creates the adjoint
            # solution associated with the lifted discrete system that is actually solved.
            adjoint_bcs = [utils.homogenize(bc) for bc in eq_bcs if isinstance(bc, backend.DirichletBC)] + [
                bc for bc in eq_bcs if not isinstance(bc, backend.DirichletBC)
            ]
            if len(adjoint_bcs) == 0:
                adjoint_bcs = None
            else:
                adjoint_bcs = misc.uniq(adjoint_bcs)

            kwargs["bcs"] = adjoint_bcs
            kwargs["solver_parameters"] = solver_parameters
            kwargs["adjoint"] = True

            if initial_guess:
                kwargs["initial_guess"] = value_coeffs[dependencies.index(initial_guess_var)]

            if replace_map:
                kwargs["replace_map"] = dict(zip(diag_coeffs, value_coeffs))

            return (
                matrix_class(
                    backend.adjoint(eq_l, reordered_arguments=ufl.algorithms.extract_arguments(eq_l)), **kwargs
                ),
                adjlinalg.Vector(None, fn_space=u.function_space()),
            )
        else:

            kwargs["bcs"] = misc.uniq(eq_bcs)
            kwargs["solver_parameters"] = solver_parameters
            kwargs["adjoint"] = False

            if initial_guess:
                kwargs["initial_guess"] = value_coeffs[dependencies.index(initial_guess_var)]

            if replace_map:
                kwargs["replace_map"] = dict(zip(diag_coeffs, value_coeffs))

            return (matrix_class(eq_l, **kwargs), adjlinalg.Vector(None, fn_space=u.function_space()))
Esempio n. 13
0
    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
Esempio n. 14
0
    def diag_action_cb(dependencies, values, hermitian, coefficient, input, context):
        value_coeffs = [v.data for v in values]
        expressions.update_expressions(frozen_expressions)
        constant.update_constants(frozen_constants)
        eq_l = backend.replace(eq_lhs, dict(zip(diag_coeffs, value_coeffs)))

        if hermitian:
            eq_l = backend.adjoint(eq_l)

        output = coefficient * backend.action(eq_l, input.data)

        return adjlinalg.Vector(output)
Esempio n. 15
0
  def __call__(self, dependencies, values):

    if isinstance(self.form, ufl.form.Form):

      dolfin_dependencies=[dep for dep in ufl.algorithms.extract_coefficients(self.form) if hasattr(dep, "function_space")]

      dolfin_values=[val.data for val in values]

      return adjlinalg.Vector(backend.replace(self.form, dict(zip(dolfin_dependencies, dolfin_values))))

    else:
      # RHS is a adjlinalg.Vector.
      assert isinstance(self.form, adjlinalg.Vector)
      return self.form
Esempio n. 16
0
    def __call__(self, dependencies, values):

        if isinstance(self.form, ufl.form.Form):

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

            dolfin_values=[val.data for val in values]

            return adjlinalg.Vector(backend.replace(self.form, dict(zip(dolfin_dependencies, dolfin_values))))

        else:
            # RHS is a adjlinalg.Vector.
            assert isinstance(self.form, adjlinalg.Vector)
            return self.form
Esempio n. 17
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.")
Esempio n. 18
0
    def __call__(self, dependencies, values):

        if isinstance(self.form, ufl.form.Form):

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

            dolfin_values = [val.data for val in values]

            return adjlinalg.Vector(
                backend.replace(self.form,
                                dict(zip(dolfin_dependencies, dolfin_values))))

        else:
            # RHS is a adjlinalg.Vector.
            assert isinstance(self.form, adjlinalg.Vector)
            return self.form
Esempio n. 19
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)
Esempio n. 20
0
                def trapezoidal(interval, iteration):
                # Evaluate the trapezoidal rule for the given interval and
                # iteration. Iteration is used to select start and end of timestep.
                    this_interval=_slice_intersect(interval, term.time)
                    if this_interval:
                        # Get adj_variables for dependencies. Time level is not yet specified.

                        # Dependency replacement dictionary.
                        replace={}

                        term_deps = _coeffs(adjointer, term.form)
                        term_vars = _vars(adjointer, term.form)

                        for term_dep, term_var in zip(term_deps,term_vars):
                            this_var = self.get_vars(adjointer, timestep, term_var)[iteration]
                            replace[term_dep] = deps[str(this_var)]

                        # Trapezoidal rule over given interval.
                        quad_weight = 0.5*(this_interval.stop-this_interval.start)

                        return backend.replace(quad_weight*term.form, replace)
Esempio n. 21
0
    def axpy(self, alpha, x):
        assert isinstance(x.data, ufl.Form)
        assert isinstance(self.data, ufl.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
        self.bcs += x.bcs # Err, I hope they are compatible ...
        self.bcs = misc.uniq(self.bcs)
Esempio n. 22
0
                def trapezoidal(interval, iteration):
                    # Evaluate the trapezoidal rule for the given interval and
                    # iteration. Iteration is used to select start and end of timestep.
                    this_interval = _slice_intersect(interval, term.time)
                    if this_interval:
                        # Get adj_variables for dependencies. Time level is not yet specified.

                        # Dependency replacement dictionary.
                        replace = {}

                        term_deps = _coeffs(adjointer, term.form)
                        term_vars = _vars(adjointer, term.form)

                        for term_dep, term_var in zip(term_deps, term_vars):
                            this_var = self.get_vars(adjointer, timestep,
                                                     term_var)[iteration]
                            replace[term_dep] = deps[str(this_var)]

                        # Trapezoidal rule over given interval.
                        quad_weight = 0.5 * (this_interval.stop -
                                             this_interval.start)

                        return backend.replace(quad_weight * term.form,
                                               replace)
Esempio n. 23
0
 def set_dependencies(self, dependencies, values):
     replace_dict = dict(zip(self.dependencies(), values))
     self.current_form = backend.replace(self.original_form, replace_dict)
Esempio n. 24
0
    def _substitute_form(self, adjointer, timestep, dependencies, values):
        ''' Perform the substitution of the dependencies and values
        provided. This is common to __call__ and __derivative__'''

        deps = {}
        for dep, val in zip(dependencies, values):
            deps[str(dep)] = val.data

        functional_value = None
        final_time = _time_levels(adjointer, adjointer.timestep_count - 1)[1]

        # Get the necessary timestep information about the adjointer.
        # For integrals, we're integrating over /two/ timesteps.
        timestep_start, timestep_end = _time_levels(adjointer, timestep)
        point_interval = slice(timestep_start, timestep_end)

        if timestep > 0:
            prev_start, prev_end = _time_levels(adjointer, timestep - 1)
            integral_interval = slice(prev_start, timestep_end)
        else:
            integral_interval = slice(timestep_start, timestep_end)

        for term in self.timeform.terms:
            if isinstance(term.time, slice):
            # Integral.

                def trapezoidal(interval, iteration):
                # Evaluate the trapezoidal rule for the given interval and
                # iteration. Iteration is used to select start and end of timestep.
                    this_interval=_slice_intersect(interval, term.time)
                    if this_interval:
                        # Get adj_variables for dependencies. Time level is not yet specified.

                        # Dependency replacement dictionary.
                        replace={}

                        term_deps = _coeffs(adjointer, term.form)
                        term_vars = _vars(adjointer, term.form)

                        for term_dep, term_var in zip(term_deps,term_vars):
                            this_var = self.get_vars(adjointer, timestep, term_var)[iteration]
                            replace[term_dep] = deps[str(this_var)]

                        # Trapezoidal rule over given interval.
                        quad_weight = 0.5*(this_interval.stop-this_interval.start)

                        return backend.replace(quad_weight*term.form, replace)

                # Calculate the integral contribution from the previous time level.
                functional_value = _add(functional_value, trapezoidal(integral_interval, 0))

                # On the final occasion, also calculate the contribution from the
                # current time level.
                if adjointer.finished and timestep == adjointer.timestep_count - 1: # we're at the end, and need to add the extra terms
                                                                                    # associated with that
                    final_interval = slice(timestep_start, timestep_end)
                    functional_value = _add(functional_value, trapezoidal(final_interval, 1))

            else:
                # Point evaluation.

                if point_interval.start < term.time < point_interval.stop:
                    replace = {}

                    term_deps = _coeffs(adjointer, term.form)
                    term_vars = _vars(adjointer, term.form)

                    for term_dep, term_var in zip(term_deps, term_vars):
                        (start, end) = self.get_vars(adjointer, timestep, term_var)
                        theta = 1.0 - (term.time - point_interval.start)/(point_interval.stop - point_interval.start)
                        replace[term_dep] = theta*deps[str(start)] + (1-theta)*deps[str(end)]

                    functional_value = _add(functional_value, backend.replace(term.form, replace))

                # Special case for evaluation at the end of time: we can't pass over to the
                # right-hand timestep, so have to do it here.
                elif (term.time == final_time or isinstance(term.time, FinishTimeConstant)) and point_interval.stop == final_time:
                    replace = {}

                    term_deps = _coeffs(adjointer, term.form)
                    term_vars = _vars(adjointer, term.form)

                    for term_dep, term_var in zip(term_deps, term_vars):
                        end = self.get_vars(adjointer, timestep, term_var)[1]
                        replace[term_dep] = deps[str(end)]

                    functional_value = _add(functional_value, backend.replace(term.form, replace))

                # Another special case for the start of a timestep.
                elif (isinstance(term.time, StartTimeConstant) and timestep == 0) or point_interval.start == term.time:
                    replace = {}

                    term_deps = _coeffs(adjointer, term.form)
                    term_vars = _vars(adjointer, term.form)

                    for term_dep, term_var in zip(term_deps, term_vars):
                        end = self.get_vars(adjointer, timestep, term_var)[0]
                        replace[term_dep] = deps[str(end)]

                    functional_value = _add(functional_value, backend.replace(term.form, replace))

        return functional_value
Esempio n. 25
0
    def _substitute_form(self, adjointer, timestep, dependencies, values):
        ''' Perform the substitution of the dependencies and values
        provided. This is common to __call__ and __derivative__'''

        deps = {}
        for dep, val in zip(dependencies, values):
            deps[str(dep)] = val.data

        functional_value = None
        final_time = _time_levels(adjointer, adjointer.timestep_count - 1)[1]

        # Get the necessary timestep information about the adjointer.
        # For integrals, we're integrating over /two/ timesteps.
        timestep_start, timestep_end = _time_levels(adjointer, timestep)
        point_interval = slice(timestep_start, timestep_end)

        if timestep > 0:
            prev_start, prev_end = _time_levels(adjointer, timestep - 1)
            integral_interval = slice(prev_start, timestep_end)
        else:
            integral_interval = slice(timestep_start, timestep_end)

        for term in self.timeform.terms:
            if isinstance(term.time, slice):
                # Integral.

                def trapezoidal(interval, iteration):
                    # Evaluate the trapezoidal rule for the given interval and
                    # iteration. Iteration is used to select start and end of timestep.
                    this_interval = _slice_intersect(interval, term.time)
                    if this_interval:
                        # Get adj_variables for dependencies. Time level is not yet specified.

                        # Dependency replacement dictionary.
                        replace = {}

                        term_deps = _coeffs(adjointer, term.form)
                        term_vars = _vars(adjointer, term.form)

                        for term_dep, term_var in zip(term_deps, term_vars):
                            this_var = self.get_vars(adjointer, timestep,
                                                     term_var)[iteration]
                            replace[term_dep] = deps[str(this_var)]

                        # Trapezoidal rule over given interval.
                        quad_weight = 0.5 * (this_interval.stop -
                                             this_interval.start)

                        return backend.replace(quad_weight * term.form,
                                               replace)

                # Calculate the integral contribution from the previous time level.
                functional_value = _add(functional_value,
                                        trapezoidal(integral_interval, 0))

                # On the final occasion, also calculate the contribution from the
                # current time level.
                if adjointer.finished and timestep == adjointer.timestep_count - 1:  # we're at the end, and need to add the extra terms
                    # associated with that
                    final_interval = slice(timestep_start, timestep_end)
                    functional_value = _add(functional_value,
                                            trapezoidal(final_interval, 1))

            else:
                # Point evaluation.

                if point_interval.start < term.time < point_interval.stop:
                    replace = {}

                    term_deps = _coeffs(adjointer, term.form)
                    term_vars = _vars(adjointer, term.form)

                    for term_dep, term_var in zip(term_deps, term_vars):
                        (start, end) = self.get_vars(adjointer, timestep,
                                                     term_var)
                        theta = float(
                            1.0 - (term.time - point_interval.start) /
                            (point_interval.stop - point_interval.start))
                        replace[term_dep] = theta * deps[str(start)] + (
                            1 - theta) * deps[str(end)]

                    functional_value = _add(
                        functional_value, backend.replace(term.form, replace))

                # Special case for evaluation at the end of time: we can't pass over to the
                # right-hand timestep, so have to do it here.
                elif (term.time == final_time
                      or isinstance(term.time, FinishTimeConstant)
                      ) and point_interval.stop == final_time:
                    replace = {}

                    term_deps = _coeffs(adjointer, term.form)
                    term_vars = _vars(adjointer, term.form)

                    for term_dep, term_var in zip(term_deps, term_vars):
                        end = self.get_vars(adjointer, timestep, term_var)[1]
                        replace[term_dep] = deps[str(end)]

                    functional_value = _add(
                        functional_value, backend.replace(term.form, replace))

                # Another special case for the start of a timestep.
                elif (isinstance(term.time, StartTimeConstant)
                      and timestep == 0) or point_interval.start == term.time:
                    replace = {}

                    term_deps = _coeffs(adjointer, term.form)
                    term_vars = _vars(adjointer, term.form)

                    for term_dep, term_var in zip(term_deps, term_vars):
                        end = self.get_vars(adjointer, timestep, term_var)[0]
                        replace[term_dep] = deps[str(end)]

                    functional_value = _add(
                        functional_value, backend.replace(term.form, replace))

        return functional_value
Esempio n. 26
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 = backend.Function(x.data)
                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):
                self.data.vector().axpy(alpha, x.data.vector())
            else:
                # This occurs when adding a RHS derivative to an adjoint equation
                # corresponding to the initial conditions.
                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()

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

        self.zero = False
Esempio n. 27
0
 def set_dependencies(self, dependencies, values):
   replace_dict = dict(zip(self.dependencies(), values))
   self.current_form = backend.replace(self.original_form, replace_dict)