def adjoint(form, reordered_arguments = None, adjoint_arguments = None): """ Wrapper for the DOLFIN adjoint function. Accepts the additional optional adjoint_arguments, which if supplied should be a tuple of Argument s corresponding to the adjoint test and trial functions. Correctly handles QForm s. """ if adjoint_arguments is None: a_form = dolfin.adjoint(form, reordered_arguments = reordered_arguments) elif not reordered_arguments is None: raise InvalidArgumentException("Cannot supply both reordered_arguments and adjoint_arguments keyword arguments") else: if not len(adjoint_arguments) == 2 \ or not isinstance(adjoint_arguments[0], ufl.argument.Argument) \ or not isinstance(adjoint_arguments[1], ufl.argument.Argument): raise InvalidArgumentException("adjoint_arguments must be a pair of Argument s") a_test, a_trial = adjoint_arguments a_form = dolfin.adjoint(form) test, trial = extract_test_and_trial(a_form) if not test.element() == a_test.element() or not trial.element() == a_trial.element(): raise InvalidArgumentException("Invalid adjoint_arguments") a_form = replace(a_form, {test:a_test, trial:a_trial}) if isinstance(form, QForm): return QForm(a_form, quadrature_degree = form.quadrature_degree()) else: return a_form
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 adjoint(form, reordered_arguments=None, adjoint_arguments=None): """ Wrapper for the DOLFIN adjoint function. Accepts the additional optional adjoint_arguments, which if supplied should be a tuple of Argument s corresponding to the adjoint test and trial functions. """ if adjoint_arguments is None: a_form = dolfin.adjoint(form, reordered_arguments=reordered_arguments) elif not reordered_arguments is None: raise InvalidArgumentException( "Cannot supply both reordered_arguments and adjoint_arguments keyword arguments" ) else: if not len(adjoint_arguments) == 2 \ or not isinstance(adjoint_arguments[0], ufl.argument.Argument) \ or not isinstance(adjoint_arguments[1], ufl.argument.Argument): raise InvalidArgumentException( "adjoint_arguments must be a pair of Argument s") a_test, a_trial = adjoint_arguments a_form = dolfin.adjoint(form) test, trial = extract_test_and_trial(a_form) if not test.element() == a_test.element() or not trial.element( ) == a_trial.element(): raise InvalidArgumentException("Invalid adjoint_arguments") a_form = dolfin.replace(a_form, {test: a_test, trial: a_trial}) return a_form
def _assemble_operator_for_stability_factor_impl(self_, term): if term == "stability_factor_left_hand_matrix": return tuple(f + adjoint(f) for f in assemble_operator(self_, "a")) elif term == "stability_factor_right_hand_matrix": return assemble_operator(self_, "inner_product") elif term == "stability_factor_dirichlet_bc": original_dirichlet_bcs = assemble_operator(self_, "dirichlet_bc") zeroed_dirichlet_bcs = list() for original_dirichlet_bc in original_dirichlet_bcs: zeroed_dirichlet_bc = list() for original_dirichlet_bc_i in original_dirichlet_bc: args = list() args.append(original_dirichlet_bc_i.function_space()) zero_value = Constant( zeros(original_dirichlet_bc_i.value().ufl_shape)) args.append(zero_value) args.extend(original_dirichlet_bc_i._domain) kwargs = original_dirichlet_bc_i._kwargs zeroed_dirichlet_bc.append(DirichletBC(*args, **kwargs)) assert len(zeroed_dirichlet_bc) == len(original_dirichlet_bc) zeroed_dirichlet_bcs.append(zeroed_dirichlet_bc) assert len(zeroed_dirichlet_bcs) == len(original_dirichlet_bcs) return tuple(zeroed_dirichlet_bcs) else: return assemble_operator(self_, term)
def assembleA(self, x, assemble_adjoint=False, assemble_rhs=False): """ Assemble the matrices and rhs for the forward/adjoint problems """ trial = dl.TrialFunction(self.Vh[STATE]) test = dl.TestFunction(self.Vh[STATE]) c = vector2Function(x[PARAMETER], self.Vh[PARAMETER]) Avarf = dl.inner( dl.exp(c) * dl.nabla_grad(trial), dl.nabla_grad(test)) * dl.dx if not assemble_adjoint: bform = dl.inner(self.f, test) * dl.dx Matrix, rhs = dl.assemble_system(Avarf, bform, self.bc) else: # Assemble the adjoint of A (i.e. the transpose of A) s = vector2Function(x[STATE], self.Vh[STATE]) bform = dl.inner(dl.Constant(0.), test) * dl.dx Matrix, _ = dl.assemble_system(dl.adjoint(Avarf), bform, self.bc0) Bu = -(self.B * x[STATE]) Bu += self.u_o rhs = dl.Vector() self.B.init_vector(rhs, 1) self.B.transpmult(Bu, rhs) rhs *= 1.0 / self.noise_variance if assemble_rhs: return Matrix, rhs else: return Matrix
def block_adjoint(block_form): assert isinstance(block_form, (array, list, BlockForm2)) if isinstance(block_form, (array, list)): input_type = array (block_form, block_function_space, block_form_rank) = _block_form_preprocessing(block_form) assert block_form_rank == 2 N = len(block_form) M = len(block_form[0]) block_adjoint_function_space = [block_function_space[1], block_function_space[0]] else: input_type = BlockForm2 N = block_form.block_size(0) M = block_form.block_size(1) block_adjoint_function_space = [block_form.block_function_spaces(1), block_form.block_function_spaces(0)] block_test_function_adjoint = BlockTestFunction(block_adjoint_function_space[0]) block_trial_function_adjoint = BlockTrialFunction(block_adjoint_function_space[1]) block_adjoint_form = empty((M, N), dtype=object) for I in range(N): for J in range(M): assert isinstance(block_form[I, J], Form) or _is_zero(block_form[I, J]) if isinstance(block_form[I, J], Form): block_adjoint_form[J, I] = adjoint(block_form[I, J], (block_test_function_adjoint[J], block_trial_function_adjoint[I])) elif _is_zero(block_form[I, J]): block_adjoint_form[J, I] = 0 else: raise TypeError("Invalid form") if input_type is array: return block_adjoint_form elif input_type is BlockForm2: return BlockForm2(block_adjoint_form, block_function_space=block_adjoint_function_space)
def compile_adjoint_jacobian(self): """Compute the adjoint of the first variation of the constraint form. This method only has side effects. """ self.compile_constraint_jacobian() self.__adjoint_jacobian = adjoint(self.__constraint_jacobian) return
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 set_forms(self, unknown, geom_ord=[0]): """ Set up weak forms of elliptic PDE. """ if any(s >= 0 for s in geom_ord): ## forms for forward equation ## # 4. Define variational problem # functions if not hasattr(self, 'states_fwd'): self.states_fwd = df.Function(self.W) # u, l = df.split(self.states_fwd) u, l = df.TrialFunctions(self.W) v, m = df.TestFunctions(self.W) f = self._source_term(degree=2) # variational forms if 'true' in str(type(unknown)): unknown = df.interpolate(unknown, self.V) self.F = df.exp(unknown) * df.inner( df.grad(u), df.grad(v)) * df.dx + ( u * m + v * l) * self.ds - f * v * df.dx + self.nugg * l * m * df.dx # self.dFdstates = df.derivative(self.F, self.states_fwd) # Jacobian # self.a = unknown*df.inner(df.grad(u), df.grad(v))*df.dx + (u*m + v*l)*self.ds + self.nugg*l*m*df.dx # self.L = f*v*df.dx if any(s >= 1 for s in geom_ord): ## forms for adjoint equation ## # Set up the objective functional J # u,_,_ = df.split(self.states_fwd) # J_form = obj.form(u) # Compute adjoint of forward operator F2 = df.action(self.F, self.states_fwd) self.dFdstates = df.derivative( F2, self.states_fwd) # linearized forward operator args = ufl.algorithms.extract_arguments( self.dFdstates) # arguments for bookkeeping self.adj_dFdstates = df.adjoint( self.dFdstates, reordered_arguments=args ) # adjoint linearized forward operator # self.dJdstates = df.derivative(J_form, self.states_fwd, df.TestFunction(self.W)) # derivative of functional with respect to solution # self.dirac_1 = obj.ptsrc(u,1) # dirac_1 cannot be initialized here because it involves evaluation ## forms for gradient ## self.dFdunknown = df.derivative(F2, unknown) self.adj_dFdunknown = df.adjoint(self.dFdunknown)
def is_self_adjoint_form(form): """ Return True if the supplied Form is self-adjoint. May return false negatives. """ if not isinstance(form, ufl.form.Form): raise InvalidArgumentException("form must be a Form") a_form = dolfin.adjoint(form) test, trial = extract_test_and_trial(form) a_test, a_trial = extract_test_and_trial(a_form) if not test.element() == a_trial.element(): return False elif not trial.element() == a_test.element(): return False a_form = dolfin.replace(a_form, {a_test:trial, a_trial:test}) return expand(form) == expand(a_form)
def assembleA(self,x, assemble_adjoint = False, assemble_rhs = False): """ Assemble the matrices and rhs for the forward/adjoint problems """ trial = dl.TrialFunction(self.Vh[STATE]) test = dl.TestFunction(self.Vh[STATE]) m = vector2Function(x[PARAMETER], self.Vh[PARAMETER]) Avarf = ufl.inner(ufl.exp(m)*sigma(trial), strain(test))*ufl.dx if not assemble_adjoint: bform = ufl.inner(self.f, test)*ufl.dx Matrix, rhs = dl.assemble_system(Avarf, bform, self.bc) else: # Assemble the adjoint of A (i.e. the transpose of A) u = vector2Function(x[STATE], self.Vh[STATE]) obs = vector2Function(self.u_o, self.Vh[STATE]) bform = ufl.inner(obs - u, test)*ufl.dx Matrix, rhs = dl.assemble_system(dl.adjoint(Avarf), bform, self.bc0) if assemble_rhs: return Matrix, rhs else: return Matrix
def assembleA(self,x, assemble_adjoint = False, assemble_rhs = False): """ Assemble the matrices and rhs for the forward/adjoint problems """ trial = dl.TrialFunction(self.Vh[STATE]) test = dl.TestFunction(self.Vh[STATE]) m = vector2Function(x[PARAMETER], self.Vh[PARAMETER]) Avarf = dl.inner(dl.exp(m)*dl.grad(trial), dl.grad(test))*dl.dx if not assemble_adjoint: bform = dl.inner(self.f, test)*dl.dx Matrix, rhs = dl.assemble_system(Avarf, bform, self.bc) else: # Assemble the adjoint of A (i.e. the transpose of A) u = vector2Function(x[STATE], self.Vh[STATE]) obs = vector2Function(self.u_o, self.Vh[STATE]) bform = dl.inner(obs - u, test)*dl.dx Matrix, rhs = dl.assemble_system(dl.adjoint(Avarf), bform, self.bc0) if assemble_rhs: return Matrix, rhs else: return Matrix