def transpose_operators(operators): out = [None, None] for i in range(2): op = operators[i] if op is None: out[i] = None elif isinstance(op, backend.cpp.GenericMatrix): out[i] = op.__class__() backend.assemble(backend.adjoint(op.form), tensor=out[i]) if hasattr(op, 'bcs'): adjoint_bcs = [backend.homogenize(bc) for bc in op.bcs if isinstance(bc, backend.cpp.DirichletBC)] + [bc for bc in op.bcs if not isinstance(bc, backend.DirichletBC)] [bc.apply(out[i]) for bc in adjoint_bcs] elif isinstance(op, backend.Form) or isinstance(op, ufl.form.Form): out[i] = backend.adjoint(op) if hasattr(op, 'bcs'): out[i].bcs = [backend.homogenize(bc) for bc in op.bcs if isinstance(bc, backend.cpp.DirichletBC)] + [bc for bc in op.bcs if not isinstance(bc, backend.DirichletBC)] elif isinstance(op, AdjointKrylovMatrix): pass else: print "op.__class__: ", op.__class__ raise libadjoint.exceptions.LibadjointErrorNotImplemented("Don't know how to transpose anything else!") return out
def solve(self, var, b): timer = backend.Timer("Matrix-free solver") solver = backend.PETScKrylovSolver(*self.solver_parameters) solver.parameters.update(self.parameters) x = backend.Function(self.fn_space) if b.data is None: backend.info_red("Warning: got zero RHS for the solve associated with variable %s" % var) return adjlinalg.Vector(x) if isinstance(b.data, backend.Function): rhs = b.data.vector().copy() else: rhs = backend.assemble(b.data) if var.type in ['ADJ_TLM', 'ADJ_ADJOINT']: self.bcs = [backend.homogenize(bc) for bc in self.bcs if isinstance(bc, backend.cpp.DirichletBC)] + [bc for bc in self.bcs if not isinstance(bc, backend.DirichletBC)] for bc in self.bcs: bc.apply(rhs) if self.operators[1] is not None: # we have a user-supplied preconditioner solver.set_operators(self.data, self.operators[1]) solver.solve(backend.down_cast(x.vector()), backend.down_cast(rhs)) else: solver.solve(self.data, backend.down_cast(x.vector()), backend.down_cast(rhs)) timer.stop() return adjlinalg.Vector(x)
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 = [backend.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_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 expressions.update_expressions(frozen_expressions_dict) value_coeffs=[v.data for v in values] eq_l = eq_lhs if hermitian: adjoint_bcs = [backend.homogenize(bc) for bc in bcs if isinstance(bc, backend.DirichletBC)] + [bc for bc in bcs if not isinstance(bc, backend.DirichletBC)] if len(adjoint_bcs) == 0: adjoint_bcs = None return (adjlinalg.Matrix(backend.adjoint(eq_l), bcs=adjoint_bcs), adjlinalg.Vector(None, fn_space=fn_space)) else: return (adjlinalg.Matrix(eq_l, bcs=bcs), adjlinalg.Vector(None, fn_space=fn_space))
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 = [backend.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 hermitian(self): adjoint_bcs = [backend.homogenize(bc) for bc in self.bcs if isinstance(bc, backend.cpp.DirichletBC)] + [bc for bc in self.bcs if not isinstance(bc, backend.DirichletBC)] return AdjointKrylovMatrix(backend.adjoint(self.original_form), bcs=adjoint_bcs)