def _forward_solve(self, lhs, rhs, func, bcs, **kwargs): solver = self.block_helper.forward_solver if solver is None: solver = backend.KrylovSolver(self.method, self.preconditioner) if self.assemble_system: A, _ = backend.assemble_system(lhs, rhs, bcs) if self.pc_operator is not None: P = self._replace_form(self.pc_operator) P, _ = backend.assemble_system(P, rhs, bcs) solver.set_operators(A, P) else: solver.set_operator(A) else: A = compat.assemble_adjoint_value(lhs) [bc.apply(A) for bc in bcs] if self.pc_operator is not None: P = self._replace_form(self.pc_operator) P = compat.assemble_adjoint_value(P) [bc.apply(P) for bc in bcs] solver.set_operators(A, P) else: solver.set_operator(A) 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.krylov_solver_parameters) solver.solve(func.vector(), b) return func
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: solver = backend.PETScKrylovSolver(self.method, self.preconditioner) solver.ksp().setOptionsPrefix(self.ksp_options_prefix) solver.set_from_options() 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) if self._ad_nullspace is not None: as_backend_type(A).set_nullspace(self._ad_nullspace) if self.pc_operator is not None: P = self._replace_form(self.pc_operator) P, _ = backend.assemble_system(P, rhs_bcs_form, bcs) solver.set_operators(A, P) else: solver.set_operator(A) else: A = compat.assemble_adjoint_value(dFdu_adj_form) [bc.apply(A) for bc in bcs] if self._ad_nullspace is not None: as_backend_type(A).set_nullspace(self._ad_nullspace) if self.pc_operator is not None: P = self._replace_form(self.pc_operator) P = compat.assemble_adjoint_value(P) [bc.apply(P) for bc in bcs] solver.set_operators(A, P) else: solver.set_operator(A) self.block_helper.adjoint_solver = solver solver.parameters.update(self.krylov_solver_parameters) [bc.apply(dJdu) for bc in bcs] if self._ad_nullspace is not None: if self._ad_nullspace._ad_orthogonalized: self._ad_nullspace.orthogonalize(dJdu) 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 _forward_solve(self, lhs, rhs, func, bcs, **kwargs): solver = self.block_helper.forward_solver if solver is None: solver = backend.PETScKrylovSolver(self.method, self.preconditioner) solver.ksp().setOptionsPrefix(self.ksp_options_prefix) solver.set_from_options() if self.assemble_system: A, _ = backend.assemble_system(lhs, rhs, bcs) if self._ad_nullspace is not None: as_backend_type(A).set_nullspace(self._ad_nullspace) if self.pc_operator is not None: P = self._replace_form(self.pc_operator) P, _ = backend.assemble_system(P, rhs, bcs) solver.set_operators(A, P) else: solver.set_operator(A) else: A = compat.assemble_adjoint_value(lhs) [bc.apply(A) for bc in bcs] if self._ad_nullspace is not None: as_backend_type(A).set_nullspace(self._ad_nullspace) if self.pc_operator is not None: P = self._replace_form(self.pc_operator) P = compat.assemble_adjoint_value(P) [bc.apply(P) for bc in bcs] solver.set_operators(A, P) else: solver.set_operator(A) 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] if self._ad_nullspace is not None: if self._ad_nullspace._ad_orthogonalized: self._ad_nullspace.orthogonalize(b) solver.parameters.update(self.krylov_solver_parameters) solver.solve(func.vector(), b) return func
def assemble_system(*args, **kwargs): """When a form is assembled, the information about its nonlinear dependencies is lost, and it is no longer easy to manipulate. Therefore, fenics_adjoint overloads the :py:func:`dolfin.assemble_system` function to *attach the form to the assembled object*. This lets the automatic annotation work, even when the user calls the lower-level :py:data:`solve(A, x, b)`. """ A_form = args[0] b_form = args[1] A, b = backend.assemble_system(*args, **kwargs) if "bcs" in kwargs: bcs = kwargs["bcs"] elif len(args) > 2: bcs = args[2] else: bcs = [] A.form = A_form A.bcs = bcs b.form = b_form b.bcs = bcs A.assemble_system = True return A, b
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): dJdu_copy = dJdu.copy() bcs = self._homogenize_bcs() 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 = backend.assemble(dFdu_adj_form) [bc.apply(A) for bc in bcs] [bc.apply(dJdu) for bc in bcs] adj_sol = compat.create_function(self.function_space) compat.linalg_solve(A, adj_sol.vector(), dJdu, *self.adj_args, **self.adj_kwargs) 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 _forward_solve(self, lhs, rhs, func, bcs, **kwargs): if self.assemble_system: A, b = backend.assemble_system(lhs, rhs, bcs) else: A = backend.assemble(lhs) b = backend.assemble(rhs) [bc.apply(A, b) for bc in bcs] if self.ident_zeros_tol is not None: A.ident_zeros(self.ident_zeros_tol) backend.solve(A, func.vector(), b, *self.forward_args, **self.forward_kwargs) return func
def assemble_system(*args, **kwargs): """When a form is assembled, the information about its nonlinear dependencies is lost, and it is no longer easy to manipulate. Therefore, dolfin_adjoint overloads the :py:func:`dolfin.assemble_system` function to *attach the form to the assembled object*. This lets the automatic annotation work, even when the user calls the lower-level :py:data:`solve(A, x, b)`. """ lhs = args[0] rhs = args[1] caching.assembled_fwd_forms.add(lhs) caching.assembled_fwd_forms.add(rhs) cache = kwargs.pop("cache", False) if 'bcs' in kwargs: bcs = kwargs['bcs'] elif len(args) > 2: bcs = args[2] else: bcs = [] if not isinstance(bcs, list): bcs = [bcs] to_annotate = utils.to_annotate(kwargs.pop("annotate", None)) (lhs_out, rhs_out) = backend.assemble_system(*args, **kwargs) if to_annotate: lhs_out.form = lhs lhs_out.bcs = bcs lhs_out.assemble_system = True rhs_out.form = rhs rhs_out.bcs = bcs rhs_out.assemble_system = True if cache: caching.assembled_adj_forms[lhs] = lhs_out caching.assembled_adj_forms[rhs] = rhs_out return (lhs_out, rhs_out)
def assemble_system(*args, **kwargs): """When a form is assembled, the information about its nonlinear dependencies is lost, and it is no longer easy to manipulate. Therefore, dolfin_adjoint overloads the :py:func:`dolfin.assemble_system` function to *attach the form to the assembled object*. This lets the automatic annotation work, even when the user calls the lower-level :py:data:`solve(A, x, b)`. """ lhs = args[0] rhs = args[1] caching.assembled_fwd_forms.add(lhs) caching.assembled_fwd_forms.add(rhs) cache = kwargs.pop("cache", False) if "bcs" in kwargs: bcs = kwargs["bcs"] elif len(args) > 2: bcs = args[2] else: bcs = [] if not isinstance(bcs, list): bcs = [bcs] (lhs_out, rhs_out) = backend.assemble_system(*args, **kwargs) to_annotate = utils.to_annotate(kwargs.pop("annotate", None)) if to_annotate: lhs_out.form = lhs lhs_out.bcs = bcs lhs_out.assemble_system = True rhs_out.form = rhs rhs_out.bcs = bcs rhs_out.assemble_system = True if cache: caching.assembled_adj_forms[lhs] = lhs_out caching.assembled_adj_forms[rhs] = rhs_out return (lhs_out, rhs_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