def _assemble_and_solve_adj_eq(self, dFdu_adj_form, dJdu, compute_bdy): dJdu_copy = dJdu.copy() bcs = self._homogenize_bcs() solver = self.block_helper.adjoint_solver if solver is None: if self.assemble_system: rhs_bcs_form = backend.inner( backend.Function(self.function_space), dFdu_adj_form.arguments()[0]) * backend.dx A, _ = backend.assemble_system(dFdu_adj_form, rhs_bcs_form, bcs) else: A = compat.assemble_adjoint_value(dFdu_adj_form) [bc.apply(A) for bc in bcs] solver = backend.LUSolver(A, self.method) self.block_helper.adjoint_solver = solver solver.parameters.update(self.lu_solver_parameters) [bc.apply(dJdu) for bc in bcs] adj_sol = backend.Function(self.function_space) solver.solve(adj_sol.vector(), dJdu) adj_sol_bdy = None if compute_bdy: adj_sol_bdy = compat.function_from_vector( self.function_space, dJdu_copy - compat.assemble_adjoint_value( backend.action(dFdu_adj_form, adj_sol))) return adj_sol, adj_sol_bdy
def _assemble_and_solve_adj_eq(self, dFdu_adj_form, dJdu, compute_bdy=True): dJdu_copy = dJdu.copy() dFdu = compat.assemble_adjoint_value(dFdu_adj_form, **self.assemble_kwargs) bcs = self._homogenize_bcs() # Apply boundary conditions on adj_dFdu and dJdu. for bc in bcs: bc.apply(dFdu, dJdu) adj_sol = compat.create_function(self.function_space) lu_solver_methods = backend.lu_solver_methods() solver_method = self.adj_args[0] if len( self.adj_args) >= 1 else "default" solver_method = "default" if solver_method == "lu" else solver_method if solver_method in lu_solver_methods: solver = backend.LUSolver(solver_method) solver_parameters = self.adj_kwargs.get("lu_solver", {}) else: solver = backend.KrylovSolver(*self.adj_args) solver_parameters = self.adj_kwargs.get("krylov_solver", {}) solver.parameters.update(solver_parameters) solver.solve(dFdu, adj_sol.vector(), dJdu) adj_sol_bdy = None if compute_bdy: adj_sol_bdy = compat.function_from_vector( self.function_space, dJdu_copy - compat.assemble_adjoint_value( backend.action(dFdu_adj_form, adj_sol))) return adj_sol, adj_sol_bdy
def derivative_action(self, dependencies, values, variable, contraction_vector, hermitian): idx = dependencies.index(variable) # If you want to apply boundary conditions symmetrically in the adjoint # -- and you often do -- # then we need to have a UFL representation of all the terms in the adjoint equation. # However! # Since UFL cannot represent the identity map, # we need to find an f such that when # assemble(inner(f, v)*dx) # we get the contraction_vector.data back. # This involves inverting a mass matrix. if backend.parameters["adjoint"][ "symmetric_bcs"] and backend.__version__ <= '1.2.0': backend.info_red( "Warning: symmetric BC application requested but unavailable in dolfin <= 1.2.0." ) if backend.parameters["adjoint"][ "symmetric_bcs"] and backend.__version__ > '1.2.0': V = contraction_vector.data.function_space() v = backend.TestFunction(V) if str(V) not in adjglobals.fsp_lu: u = backend.TrialFunction(V) A = backend.assemble(backend.inner(u, v) * backend.dx) solver = "mumps" if "mumps" in backend.lu_solver_methods( ).keys() else "default" lusolver = backend.LUSolver(A, solver) lusolver.parameters["symmetric"] = True lusolver.parameters["reuse_factorization"] = True adjglobals.fsp_lu[str(V)] = lusolver else: lusolver = adjglobals.fsp_lu[str(V)] riesz = backend.Function(V) lusolver.solve( riesz.vector(), self.weights[idx] * contraction_vector.data.vector()) out = (backend.inner(riesz, v) * backend.dx) else: out = backend.Function(self.fn_space) out.assign(self.weights[idx] * contraction_vector.data) return adjlinalg.Vector(out)
def _forward_solve(self, lhs, rhs, func, bcs, **kwargs): solver = self.block_helper.forward_solver if solver is None: if self.assemble_system: A, _ = backend.assemble_system(lhs, rhs, bcs) else: A = compat.assemble_adjoint_value(lhs) [bc.apply(A) for bc in bcs] solver = backend.LUSolver(A, self.method) self.block_helper.forward_solver = solver if self.assemble_system: system_assembler = backend.SystemAssembler(lhs, rhs, bcs) b = backend.Function(self.function_space).vector() system_assembler.assemble(b) else: b = compat.assemble_adjoint_value(rhs) [bc.apply(b) for bc in bcs] solver.parameters.update(self.lu_solver_parameters) solver.solve(func.vector(), b) return func