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
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)
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
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
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)
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)
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)
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
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
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.")
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
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()))
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)
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
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
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 __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
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)
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)
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)
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)
def set_dependencies(self, dependencies, values): replace_dict = dict(zip(self.dependencies(), values)) self.current_form = backend.replace(self.original_form, replace_dict)
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
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
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