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, dolfin.cpp.GenericMatrix): out[i] = op.__class__() dolfin.assemble(dolfin.adjoint(op.form), tensor=out[i]) if hasattr(op, 'bcs'): adjoint_bcs = [utils.homogenize(bc) for bc in op.bcs if isinstance(bc, dolfin.cpp.DirichletBC)] + [bc for bc in op.bcs if not isinstance(bc, dolfin.DirichletBC)] [bc.apply(out[i]) for bc in adjoint_bcs] elif isinstance(op, dolfin.Form) or isinstance(op, ufl.form.Form): out[i] = dolfin.adjoint(op) if hasattr(op, 'bcs'): out[i].bcs = [utils.homogenize(bc) for bc in op.bcs if isinstance(bc, dolfin.cpp.DirichletBC)] + [bc for bc in op.bcs if not isinstance(bc, dolfin.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 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 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 caching_solve(self, var, b): if isinstance(self.data, IdentityMatrix): output = b.duplicate() output.axpy(1.0, b) if isinstance(output.data, ufl.Form): output = Vector(backend.Function(output.fn_space, backend.assemble(output.data))) elif b.data is None: backend.warning("Warning: got zero RHS for the solve associated with variable %s" % var) output = Vector(backend.Function(self.test_function().function_space())) else: 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 output = Vector(backend.Function(self.test_function().function_space())) #print "b.data is a %s in the solution of %s" % (b.data.__class__, var) if backend.parameters["adjoint"]["symmetric_bcs"] and backend.__version__ > '1.2.0': assembler = backend.SystemAssembler(self.data, b.data, bcs) assembled_rhs = backend.Vector() assembler.assemble(assembled_rhs) elif isinstance(b.data, ufl.Form): assembled_rhs = wrap_assemble(b.data, self.test_function()) else: if backend.__name__ == "dolfin": assembled_rhs = b.data.vector() else: assembled_rhs = b.data [bc.apply(assembled_rhs) for bc in bcs] if not var in caching.lu_solvers: if backend.parameters["adjoint"]["debug_cache"]: backend.info_red("Got a cache miss for %s" % var) if backend.parameters["adjoint"]["symmetric_bcs"] and backend.__version__ > '1.2.0': assembled_lhs = backend.Matrix() assembler.assemble(assembled_lhs) else: assembled_lhs = self.assemble_data() [bc.apply(assembled_lhs) for bc in bcs] caching.lu_solvers[var] = compatibility.LUSolver(assembled_lhs, "mumps") caching.lu_solvers[var].parameters["reuse_factorization"] = True else: if backend.parameters["adjoint"]["debug_cache"]: backend.info_green("Got a cache hit for %s" % var) caching.lu_solvers[var].solve(output.data.vector(), assembled_rhs) return output
def pixel_to_ray_vec(self, pts): """ given a pixel, calculate a line that all points will be projected to the pixel through the camera Params: pts - 2 by n array, points in image coordinates Return: d - 3 by n array, direction vector for each pixel C - 3 by 1 array, camera center in world frame, pencil of point representation. """ pts_homo = homogenize(pts) pts_norm = np.matmul(self.K_inv, pts_homo) d = np.matmul(self.R.T, pts_norm) d = d / np.sign(d[0, :]) / np.linalg.norm(d, axis=0) C = self.C_world_inhomo return d, C
def solve(self, var, b): if reuse_factorization is False: return adjlinalg.Matrix.solve(self, var, b) if var.type in ['ADJ_TLM', 'ADJ_ADJOINT']: bcs = [utils.homogenize(bc) for bc in self.bcs if isinstance(bc, dolfin.DirichletBC)] + [bc for bc in self.bcs if not isinstance(bc, dolfin.DirichletBC)] else: bcs = self.bcs if var.type in ['ADJ_FORWARD', 'ADJ_TLM']: solver = lu_solvers[idx] if solver is None: A = assembly.assemble(self.data); [bc.apply(A) for bc in bcs] lu_solvers[idx] = LUSolver(A) lu_solvers[idx].parameters["reuse_factorization"] = True solver = lu_solvers[idx] else: if adj_lu_solvers[idx] is None: A = assembly.assemble(self.data); [bc.apply(A) for bc in bcs] adj_lu_solvers[idx] = LUSolver(A) adj_lu_solvers[idx].parameters["reuse_factorization"] = True solver = adj_lu_solvers[idx] x = adjlinalg.Vector(dolfin.Function(self.test_function().function_space())) if b.data is None: # 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. dolfin.info_red("Warning: got zero RHS for the solve associated with variable %s" % var) else: if isinstance(b.data, dolfin.Function): b_vec = b.data.vector().copy() else: b_vec = dolfin.assemble(b.data) [bc.apply(b_vec) for bc in bcs] solver.solve(x.data.vector(), b_vec, annotate=False) return x
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 solve(selfmat, var, b): if selfmat.adjoint: operators = transpose_operators(selfmat.operators) else: operators = selfmat.operators # Fetch/construct the solver if var.type in ['ADJ_FORWARD', 'ADJ_TLM']: solver = petsc_krylov_solvers[idx] need_to_set_operator = self._need_to_reset_operator else: if adj_petsc_krylov_solvers[idx] is None: need_to_set_operator = True adj_petsc_krylov_solvers[idx] = PETScKrylovSolver(*solver_parameters) adj_ksp = adj_petsc_krylov_solvers[idx].ksp() fwd_ksp = petsc_krylov_solvers[idx].ksp() adj_ksp.setOptionsPrefix(fwd_ksp.getOptionsPrefix()) adj_ksp.setType(fwd_ksp.getType()) adj_ksp.pc.setType(fwd_ksp.pc.getType()) adj_ksp.setFromOptions() else: need_to_set_operator = self._need_to_reset_operator solver = adj_petsc_krylov_solvers[idx] # FIXME: work around DOLFIN bug #583 try: solver.parameters.convergence_norm_type except: solver.parameters.convergence_norm_type = "preconditioned" # end FIXME solver.parameters.update(parameters) self._need_to_reset_operator = False if selfmat.adjoint: (nsp_, tnsp_) = (tnsp, nsp) else: (nsp_, tnsp_) = (nsp, tnsp) x = dolfin.Function(fn_space) if selfmat.initial_guess is not None and var.type == 'ADJ_FORWARD': x.vector()[:] = selfmat.initial_guess.vector() if b.data is None: dolfin.info_red("Warning: got zero RHS for the solve associated with variable %s" % var) return adjlinalg.Vector(x) if var.type in ['ADJ_TLM', 'ADJ_ADJOINT']: selfmat.bcs = [utils.homogenize(bc) for bc in selfmat.bcs if isinstance(bc, dolfin.cpp.DirichletBC)] + [bc for bc in selfmat.bcs if not isinstance(bc, dolfin.cpp.DirichletBC)] # This is really hideous. Sorry. if isinstance(b.data, dolfin.Function): rhs = b.data.vector().copy() [bc.apply(rhs) for bc in selfmat.bcs] if need_to_set_operator: if assemble_system: # if we called assemble_system, rather than assemble v = dolfin.TestFunction(fn_space) (A, rhstmp) = dolfin.assemble_system(operators[0], dolfin.inner(b.data, v)*dolfin.dx, selfmat.bcs) if has_preconditioner: (P, rhstmp) = dolfin.assemble_system(operators[1], dolfin.inner(b.data, v)*dolfin.dx, selfmat.bcs) solver.set_operators(A, P) else: solver.set_operator(A) else: # we called assemble A = dolfin.assemble(operators[0]) [bc.apply(A) for bc in selfmat.bcs] if has_preconditioner: P = dolfin.assemble(operators[1]) [bc.apply(P) for bc in selfmat.bcs] solver.set_operators(A, P) else: solver.set_operator(A) else: if assemble_system: # if we called assemble_system, rather than assemble (A, rhs) = dolfin.assemble_system(operators[0], b.data, selfmat.bcs) if need_to_set_operator: if has_preconditioner: (P, rhstmp) = dolfin.assemble_system(operators[1], b.data, selfmat.bcs) solver.set_operators(A, P) else: solver.set_operator(A) else: # we called assemble A = dolfin.assemble(operators[0]) rhs = dolfin.assemble(b.data) [bc.apply(A) for bc in selfmat.bcs] [bc.apply(rhs) for bc in selfmat.bcs] if need_to_set_operator: if has_preconditioner: P = dolfin.assemble(operators[1]) [bc.apply(P) for bc in selfmat.bcs] solver.set_operators(A, P) else: solver.set_operator(A) if need_to_set_operator: print "|A|: %.6e" % A.norm("frobenius") # Set the nullspace for the linear operator if nsp_ is not None and need_to_set_operator: dolfin.as_backend_type(A).set_nullspace(nsp_) # (Possibly override the user in) orthogonalize # the right-hand-side if tnsp_ is not None: tnsp_.orthogonalize(rhs) print "%s: |b|: %.6e" % (var, rhs.norm("l2")) solver.solve(x.vector(), rhs) return adjlinalg.Vector(x)
def solve(self, var, b): if self.adjoint: operators = transpose_operators(self.operators) else: operators = self.operators solver = dolfin.LinearSolver(*solver_parameters) solver.parameters.update(parameters) x = dolfin.Function(fn_space) if self.initial_guess is not None and var.type == 'ADJ_FORWARD': x.vector()[:] = self.initial_guess.vector() if b.data is None: dolfin.info_red("Warning: got zero RHS for the solve associated with variable %s" % var) return adjlinalg.Vector(x) if var.type in ['ADJ_TLM', 'ADJ_ADJOINT']: self.bcs = [utils.homogenize(bc) for bc in self.bcs if isinstance(bc, dolfin.cpp.DirichletBC)] + [bc for bc in self.bcs if not isinstance(bc, dolfin.cpp.DirichletBC)] # This is really hideous. Sorry. if isinstance(b.data, dolfin.Function): rhs = b.data.vector().copy() [bc.apply(rhs) for bc in self.bcs] if assemble_system: # if we called assemble_system, rather than assemble v = dolfin.TestFunction(fn_space) (A, rhstmp) = dolfin.assemble_system(operators[0], dolfin.inner(b.data, v)*dolfin.dx, self.bcs) if has_preconditioner: (P, rhstmp) = dolfin.assemble_system(operators[1], dolfin.inner(b.data, v)*dolfin.dx, self.bcs) solver.set_operators(A, P) else: solver.set_operator(A) else: # we called assemble A = dolfin.assemble(operators[0]) [bc.apply(A) for bc in self.bcs] # Set nullspace if nsp: dolfin.as_backend_type(A).set_nullspace(nsp) nsp.orthogonalize(b); if has_preconditioner: P = dolfin.assemble(operators[1]) [bc.apply(P) for bc in self.bcs] solver.set_operators(A, P) else: solver.set_operator(A) else: if assemble_system: # if we called assemble_system, rather than assemble (A, rhs) = dolfin.assemble_system(operators[0], b.data, self.bcs) if has_preconditioner: (P, rhstmp) = dolfin.assemble_system(operators[1], b.data, self.bcs) solver.set_operators(A, P) else: solver.set_operator(A) else: # we called assemble A = dolfin.assemble(operators[0]) rhs = dolfin.assemble(b.data) [bc.apply(A) for bc in self.bcs] [bc.apply(rhs) for bc in self.bcs] # Set nullspace if nsp: dolfin.as_backend_type(A).set_nullspace(nsp) nsp.orthogonalize(rhs); if has_preconditioner: P = dolfin.assemble(operators[1]) [bc.apply(P) for bc in self.bcs] solver.set_operators(A, P) else: solver.set_operator(A) solver.solve(x.vector(), rhs) return adjlinalg.Vector(x)
def solve(self, var, b): if self.adjoint: operators = transpose_operators(self.operators) else: operators = self.operators # Fetch/construct the solver if var.type in ['ADJ_FORWARD', 'ADJ_TLM']: solver = krylov_solvers[idx] need_to_set_operator = False else: if adj_krylov_solvers[idx] is None: need_to_set_operator = True adj_krylov_solvers[idx] = KrylovSolver(*solver_parameters) else: need_to_set_operator = False solver = adj_krylov_solvers[idx] solver.parameters.update(parameters) if self.adjoint: (nsp_, tnsp_) = (tnsp, nsp) else: (nsp_, tnsp_) = (nsp, tnsp) x = dolfin.Function(fn_space) if self.initial_guess is not None and var.type == 'ADJ_FORWARD': x.vector()[:] = self.initial_guess.vector() if b.data is None: dolfin.info_red("Warning: got zero RHS for the solve associated with variable %s" % var) return adjlinalg.Vector(x) if var.type in ['ADJ_TLM', 'ADJ_ADJOINT']: self.bcs = [utils.homogenize(bc) for bc in self.bcs if isinstance(bc, dolfin.cpp.DirichletBC)] + [bc for bc in self.bcs if not isinstance(bc, dolfin.cpp.DirichletBC)] # This is really hideous. Sorry. if isinstance(b.data, dolfin.Function): rhs = b.data.vector().copy() [bc.apply(rhs) for bc in self.bcs] if need_to_set_operator: if assemble_system: # if we called assemble_system, rather than assemble v = dolfin.TestFunction(fn_space) (A, rhstmp) = dolfin.assemble_system(operators[0], dolfin.inner(b.data, v)*dolfin.dx, self.bcs) if has_preconditioner: (P, rhstmp) = dolfin.assemble_system(operators[1], dolfin.inner(b.data, v)*dolfin.dx, self.bcs) solver.set_operators(A, P) else: solver.set_operator(A) else: # we called assemble A = dolfin.assemble(operators[0]) [bc.apply(A) for bc in self.bcs] if has_preconditioner: P = dolfin.assemble(operators[1]) [bc.apply(P) for bc in self.bcs] solver.set_operators(A, P) else: solver.set_operator(A) else: if assemble_system: # if we called assemble_system, rather than assemble (A, rhs) = dolfin.assemble_system(operators[0], b.data, self.bcs) if need_to_set_operator: if has_preconditioner: (P, rhstmp) = dolfin.assemble_system(operators[1], b.data, self.bcs) solver.set_operators(A, P) else: solver.set_operator(A) else: # we called assemble A = dolfin.assemble(operators[0]) rhs = dolfin.assemble(b.data) [bc.apply(A) for bc in self.bcs] [bc.apply(rhs) for bc in self.bcs] if need_to_set_operator: if has_preconditioner: P = dolfin.assemble(operators[1]) [bc.apply(P) for bc in self.bcs] solver.set_operators(A, P) else: solver.set_operator(A) # Set the nullspace for the linear operator if nsp_ is not None and need_to_set_operator: dolfin.as_backend_type(A).set_nullspace(nsp_) # (Possibly override the user in) orthogonalize # the right-hand-side if tnsp_ is not None: tnsp_.orthogonalize(rhs) solver.solve(x.vector(), rhs) return adjlinalg.Vector(x)
def get_image_coordinate(self, X): """ get the image coordinate of world point X """ x_homo = np.matmul(self.P, homogenize(X)) x = dehomogenize(x_homo) return x