def taylor_test_expression(exp, V, seed=None): """ Performs a Taylor test of an Expression with dependencies. exp: The expression to test V: A suitable function space on which the expression will be projected. seed: The initial perturbation coefficient for the taylor test. Warning: This function resets the adjoint tape! """ from . import drivers, functional, projection from .controls import Control adjglobals.adj_reset() # Annotate test model s = projection.project(exp, V, annotate=True) mesh = V.mesh() Jform = s**2*backend.dx + exp*backend.dx(domain=mesh) J = functional.Functional(Jform) J0 = backend.assemble(Jform) controls = [Control(c) for c in exp.dependencies] dJd0 = drivers.compute_gradient(J, controls, forget=False) for i in range(len(controls)): def Jfunc(new_val): dep = exp.dependencies[i] # Remember the old dependency value for later old_val = float(dep) # Compute the functional value dep.assign(new_val) s = projection.project(exp, V, annotate=False) out = backend.assemble(s**2*backend.dx + exp*backend.dx(domain=mesh)) # Restore the old dependency value dep.assign(old_val) return out #HJ = hessian(J, controls[i], warn=False) #minconv = taylor_test(Jfunc, controls[i], J0, dJd0[i], HJm=HJ) minconv = taylor_test(Jfunc, controls[i], J0, dJd0[i], seed=seed) if math.isnan(minconv): warning("Convergence order is not a number. Assuming that you \ have a linear or constant constraint dependency (e.g. check that the Taylor \ remainder are all 0).") else: if not minconv > 1.9: raise Exception("The Taylor test failed when checking the \ derivative with respect to the %i'th dependency." % (i+1)) adjglobals.adj_reset()
def project_dolfin(v, V=None, bcs=None, mesh=None, solver_type="cg", preconditioner_type="default", form_compiler_parameters=None, annotate=None, name=None): '''The project call performs an equation solve, and so it too must be annotated so that the adjoint and tangent linear models may be constructed automatically by libadjoint. To disable the annotation of this function, just pass :py:data:`annotate=False`. This is useful in cases where the solve is known to be irrelevant or diagnostic for the purposes of the adjoint computation (such as projecting fields to other function spaces for the purposes of visualisation).''' to_annotate = utils.to_annotate(annotate) if isinstance(v, backend.Expression) and (annotate is not True): to_annotate = False if isinstance(v, backend.Constant) and (annotate is not True): to_annotate = False out = backend.project(v=v, V=V, bcs=bcs, mesh=mesh, solver_type=solver_type, preconditioner_type=preconditioner_type, form_compiler_parameters=form_compiler_parameters) out = utils.function_to_da_function(out) if name is not None: out.adj_name = name out.rename(name, "a Function from dolfin-adjoint") if to_annotate: # reproduce the logic from project. This probably isn't future-safe, but anyway if V is None: V = backend.fem.projection._extract_function_space(v, mesh) if mesh is None: mesh = V.mesh() # Define variational problem for projection w = backend.TestFunction(V) Pv = backend.TrialFunction(V) a = backend.inner(w, Pv)*backend.dx(domain=mesh) L = backend.inner(w, v)*backend.dx(domain=mesh) solving.annotate(a == L, out, bcs, solver_parameters={"linear_solver": solver_type, "preconditioner": preconditioner_type, "symmetric": True}) if backend.parameters["adjoint"]["record_all"]: adjglobals.adjointer.record_variable(adjglobals.adj_variables[out], libadjoint.MemoryStorage(adjlinalg.Vector(out))) return out
def taylor_test_expression(exp, V): """ Performs a Taylor test of an Expression with dependencies. exp: The expression to test V: A suitable function space on which the expression will be projected. Warning: This function resets the adjoint tape! """ adjglobals.adj_reset() # Annotate test model s = projection.project(exp, V, annotate=True) mesh = V.mesh() Jform = s**2*backend.dx + exp*backend.dx(domain=mesh) J = functional.Functional(Jform) J0 = backend.assemble(Jform) deps = exp.dependencies() controls = [Control(c) for c in deps] dJd0 = drivers.compute_gradient(J, controls, forget=False) for i in range(len(controls)): def Jfunc(new_val): dep = exp.dependencies()[i] # Remember the old dependency value for later old_val = float(dep) # Compute the functional value dep.assign(new_val) s = projection.project(exp, V, annotate=False) out = backend.assemble(s**2*backend.dx + exp*backend.dx(domain=mesh)) # Restore the old dependency value dep.assign(old_val) return out #HJ = hessian(J, controls[i], warn=False) #minconv = taylor_test(Jfunc, controls[i], J0, dJd0[i], HJm=HJ) minconv = taylor_test(Jfunc, controls[i], J0, dJd0[i]) if math.isnan(minconv): warning("Convergence order is not a number. Assuming that you \ have a linear or constant constraint dependency (e.g. check that the Taylor \ remainder are all 0).") else: if not minconv > 1.9: raise Exception, "The Taylor test failed when checking the \ derivative with respect to the %i'th dependency." % (i+1) adjglobals.adj_reset()
def __init__(self, v, V, output, bcs=[], *args, **kwargs): mesh = kwargs.pop("mesh", None) if mesh is None: mesh = V.mesh() dx = backend.dx(mesh) w = backend.TestFunction(V) Pv = backend.TrialFunction(V) a = backend.inner(w, Pv) * dx L = backend.inner(w, v) * dx super(ProjectBlock, self).__init__(a == L, output, bcs, *args, **kwargs)
def Jfunc(new_val): dep = exp.dependencies()[i] # Remember the old dependency value for later old_val = float(dep) # Compute the functional value dep.assign(new_val) s = projection.project(exp, V, annotate=False) out = backend.assemble(s**2*backend.dx + exp*backend.dx(domain=mesh)) # Restore the old dependency value dep.assign(old_val) return out
def Jfunc(new_val): dep = exp.dependencies[i] # Remember the old dependency value for later old_val = float(dep) # Compute the functional value dep.assign(new_val) s = projection.project(exp, V, annotate=False) out = backend.assemble(s**2*backend.dx + exp*backend.dx(domain=mesh)) # Restore the old dependency value dep.assign(old_val) return out
def project_dolfin(v, V=None, bcs=None, mesh=None, solver_type="lu", preconditioner_type="default", form_compiler_parameters=None, annotate=None, name=None): '''The project call performs an equation solve, and so it too must be annotated so that the adjoint and tangent linear models may be constructed automatically by libadjoint. To disable the annotation of this function, just pass :py:data:`annotate=False`. This is useful in cases where the solve is known to be irrelevant or diagnostic for the purposes of the adjoint computation (such as projecting fields to other function spaces for the purposes of visualisation).''' to_annotate = utils.to_annotate(annotate) if isinstance(v, backend.Expression) and (annotate is not True): to_annotate = False if isinstance(v, backend.Constant) and (annotate is not True): to_annotate = False out = backend.project(v=v, V=V, bcs=bcs, mesh=mesh, solver_type=solver_type, preconditioner_type=preconditioner_type, form_compiler_parameters=form_compiler_parameters) out = utils.function_to_da_function(out) if name is not None: out.adj_name = name out.rename(name, "a Function from dolfin-adjoint") if to_annotate: # reproduce the logic from project. This probably isn't future-safe, but anyway if V is None: V = backend.fem.projection._extract_function_space(v, mesh) if mesh is None: mesh = V.mesh() # Define variational problem for projection w = backend.TestFunction(V) Pv = backend.TrialFunction(V) a = backend.inner(w, Pv) * backend.dx(domain=mesh) L = backend.inner(w, v) * backend.dx(domain=mesh) solving.annotate(a == L, out, bcs, solver_parameters={ "linear_solver": solver_type, "preconditioner": preconditioner_type, "symmetric": True }) if backend.parameters["adjoint"]["record_all"]: adjglobals.adjointer.record_variable( adjglobals.adj_variables[out], libadjoint.MemoryStorage(adjlinalg.Vector(out))) return out