def evaluate_hessian_component(self, inputs, hessian_inputs, adj_inputs, block_variable, idx, relevant_dependencies, prepared=None): form = prepared hessian_input = hessian_inputs[0] adj_input = adj_inputs[0] c1 = block_variable.output c1_rep = block_variable.saved_output if isinstance(c1, backend.Function): dc = backend.TestFunction(c1.function_space()) elif isinstance(c1, compat.ExpressionType): mesh = form.ufl_domain().ufl_cargo() W = c1._ad_function_space(mesh) dc = backend.TestFunction(W) elif isinstance(c1, backend.Constant): mesh = compat.extract_mesh_from_form(form) dc = backend.TestFunction(c1._ad_function_space(mesh)) elif isinstance(c1, compat.MeshType): pass else: return None if isinstance(c1, compat.MeshType): X = backend.SpatialCoordinate(c1) dform = backend.derivative(form, X) else: dform = backend.derivative(form, c1_rep, dc) hessian_outputs = hessian_input * compat.assemble_adjoint_value(dform) for other_idx, bv in relevant_dependencies: c2_rep = bv.saved_output tlm_input = bv.tlm_value if tlm_input is None: continue if isinstance(c2_rep, compat.MeshType): X = backend.SpatialCoordinate(c2_rep) ddform = backend.derivative(dform, X, tlm_input) else: ddform = backend.derivative(dform, c2_rep, tlm_input) hessian_outputs += adj_input * compat.assemble_adjoint_value( ddform) if isinstance(c1, compat.ExpressionType): return [(hessian_outputs, W)] else: return hessian_outputs
def _assemble_soa_eq_rhs(self, dFdu_form, adj_sol, hessian_input, d2Fdu2): # Start piecing together the rhs of the soa equation b = hessian_input.copy() b_form = d2Fdu2 for bo in self.get_dependencies(): c = bo.output c_rep = bo.saved_output tlm_input = bo.tlm_value if (c == self.func and not self.linear) or tlm_input is None: continue if isinstance(c, compat.MeshType): X = backend.SpatialCoordinate(c) dFdu_adj = backend.action(backend.adjoint(dFdu_form), adj_sol) d2Fdudm = ufl.algorithms.expand_derivatives( backend.derivative(dFdu_adj, X, tlm_input)) if len(d2Fdudm.integrals()) > 0: b -= compat.assemble_adjoint_value(d2Fdudm) elif not isinstance(c, backend.DirichletBC): b_form += backend.derivative(dFdu_form, c_rep, tlm_input) b_form = ufl.algorithms.expand_derivatives(b_form) if len(b_form.integrals()) > 0: b_form = backend.adjoint(b_form) b -= compat.assemble_adjoint_value(backend.action(b_form, adj_sol)) return b
def evaluate_tlm_component(self, inputs, tlm_inputs, block_variable, idx, prepared=None): F_form = prepared["form"] dFdu = prepared["dFdu"] V = self.get_outputs()[idx].output.function_space() bcs = [] dFdm = 0. dFdm_shape = 0. for block_variable in self.get_dependencies(): tlm_value = block_variable.tlm_value c = block_variable.output c_rep = block_variable.saved_output if isinstance(c, backend.DirichletBC): if tlm_value is None: bcs.append(compat.create_bc(c, homogenize=True)) else: bcs.append(tlm_value) continue elif isinstance(c, compat.MeshType): X = backend.SpatialCoordinate(c) c_rep = X if tlm_value is None: continue if c == self.func and not self.linear: continue if isinstance(c, compat.MeshType): dFdm_shape += compat.assemble_adjoint_value( backend.derivative(-F_form, c_rep, tlm_value)) else: dFdm += backend.derivative(-F_form, c_rep, tlm_value) if isinstance(dFdm, float): v = dFdu.arguments()[0] dFdm = backend.inner(backend.Constant(numpy.zeros(v.ufl_shape)), v) * backend.dx dFdm = compat.assemble_adjoint_value(dFdm) + dFdm_shape dudm = backend.Function(V) return self._assemble_and_solve_tlm_eq( compat.assemble_adjoint_value(dFdu, bcs=bcs), dFdm, dudm, bcs)
def evaluate_adj_component(self, inputs, adj_inputs, block_variable, idx, prepared=None): if not self.linear and self.func == block_variable.output: # We are not able to calculate derivatives wrt initial guess. return None F_form = prepared["form"] adj_sol = prepared["adj_sol"] adj_sol_bdy = prepared["adj_sol_bdy"] c = block_variable.output c_rep = block_variable.saved_output if isinstance(c, backend.Function): trial_function = backend.TrialFunction(c.function_space()) elif isinstance(c, backend.Constant): mesh = compat.extract_mesh_from_form(F_form) trial_function = backend.TrialFunction(c._ad_function_space(mesh)) elif isinstance(c, compat.ExpressionType): mesh = F_form.ufl_domain().ufl_cargo() c_fs = c._ad_function_space(mesh) trial_function = backend.TrialFunction(c_fs) elif isinstance(c, backend.DirichletBC): tmp_bc = compat.create_bc(c, value=extract_subfunction( adj_sol_bdy, c.function_space())) return [tmp_bc] elif isinstance(c, compat.MeshType): # Using CoordianteDerivative requires us to do action before # differentiating, might change in the future. F_form_tmp = backend.action(F_form, adj_sol) X = backend.SpatialCoordinate(c_rep) dFdm = backend.derivative(-F_form_tmp, X) dFdm = compat.assemble_adjoint_value(dFdm, **self.assemble_kwargs) return dFdm dFdm = -backend.derivative(F_form, c_rep, trial_function) dFdm = backend.adjoint(dFdm) dFdm = dFdm * adj_sol dFdm = compat.assemble_adjoint_value(dFdm, **self.assemble_kwargs) if isinstance(c, compat.ExpressionType): return [[dFdm, c_fs]] else: return dFdm
def evaluate_adj_component(self, inputs, adj_inputs, block_variable, idx, prepared=None): form = prepared adj_input = adj_inputs[0] c = block_variable.output c_rep = block_variable.saved_output if isinstance(c, compat.ExpressionType): # Create a FunctionSpace from self.form and Expression. # And then make a TestFunction from this space. mesh = self.form.ufl_domain().ufl_cargo() V = c._ad_function_space(mesh) dc = backend.TestFunction(V) dform = backend.derivative(form, c_rep, dc) output = compat.assemble_adjoint_value(dform) return [[adj_input * output, V]] elif isinstance(c, compat.MeshType): X = backend.SpatialCoordinate(c_rep) dform = backend.derivative(form, X) output = compat.assemble_adjoint_value(dform) return adj_input * output if isinstance(c, backend.Function): dc = backend.TestFunction(c.function_space()) elif isinstance(c, backend.Constant): mesh = compat.extract_mesh_from_form(self.form) dc = backend.TestFunction(c._ad_function_space(mesh)) dform = backend.derivative(form, c_rep, dc) output = compat.assemble_adjoint_value(dform) return adj_input * output
def evaluate_tlm_component(self, inputs, tlm_inputs, block_variable, idx, prepared=None): form = prepared dform = 0. dform_shape = 0. for bv in self.get_dependencies(): c_rep = bv.saved_output tlm_value = bv.tlm_value if tlm_value is None: continue if isinstance(c_rep, compat.MeshType): X = backend.SpatialCoordinate(c_rep) dform_shape += compat.assemble_adjoint_value( backend.derivative(form, X, tlm_value)) else: dform += backend.derivative(form, c_rep, tlm_value) if not isinstance(dform, float): dform = compat.assemble_adjoint_value(dform) return dform + dform_shape
def evaluate_hessian_component(self, inputs, hessian_inputs, adj_inputs, block_variable, idx, relevant_dependencies, prepared=None): c = block_variable.output if c == self.func and not self.linear: return None adj_sol2 = prepared["adj_sol2"] adj_sol2_bdy = prepared["adj_sol2_bdy"] F_form = prepared["form"] adj_sol = prepared["adj_sol"] fwd_block_variable = self.get_outputs()[0] tlm_output = fwd_block_variable.tlm_value c_rep = block_variable.saved_output # If m = DirichletBC then d^2F(u,m)/dm^2 = 0 and d^2F(u,m)/dudm = 0, # so we only have the term dF(u,m)/dm * adj_sol2 if isinstance(c, backend.DirichletBC): tmp_bc = compat.create_bc(c, value=extract_subfunction( adj_sol2_bdy, c.function_space())) return [tmp_bc] if isinstance(c_rep, backend.Constant): mesh = compat.extract_mesh_from_form(F_form) W = c._ad_function_space(mesh) elif isinstance(c, compat.ExpressionType): mesh = F_form.ufl_domain().ufl_cargo() W = c._ad_function_space(mesh) elif isinstance(c, compat.MeshType): X = backend.SpatialCoordinate(c) element = X.ufl_domain().ufl_coordinate_element() W = backend.FunctionSpace(c, element) else: W = c.function_space() dc = backend.TestFunction(W) form_adj = backend.action(F_form, adj_sol) form_adj2 = backend.action(F_form, adj_sol2) if isinstance(c, compat.MeshType): dFdm_adj = backend.derivative(form_adj, X, dc) dFdm_adj2 = backend.derivative(form_adj2, X, dc) else: dFdm_adj = backend.derivative(form_adj, c_rep, dc) dFdm_adj2 = backend.derivative(form_adj2, c_rep, dc) # TODO: Old comment claims this might break on split. Confirm if true or not. d2Fdudm = ufl.algorithms.expand_derivatives( backend.derivative(dFdm_adj, fwd_block_variable.saved_output, tlm_output)) hessian_output = 0 # We need to add terms from every other dependency # i.e. the terms d^2F/dm_1dm_2 for _, bv in relevant_dependencies: c2 = bv.output c2_rep = bv.saved_output if isinstance(c2, backend.DirichletBC): continue tlm_input = bv.tlm_value if tlm_input is None: continue if c2 == self.func and not self.linear: continue # TODO: If tlm_input is a Sum, this crashes in some instances? if isinstance(c2_rep, compat.MeshType): X = backend.SpatialCoordinate(c2_rep) d2Fdm2 = ufl.algorithms.expand_derivatives( backend.derivative(dFdm_adj, X, tlm_input)) else: d2Fdm2 = ufl.algorithms.expand_derivatives( backend.derivative(dFdm_adj, c2_rep, tlm_input)) if d2Fdm2.empty(): continue hessian_output -= compat.assemble_adjoint_value(d2Fdm2) if not d2Fdudm.empty(): # FIXME: This can be empty in the multimesh case, ask sebastian hessian_output -= compat.assemble_adjoint_value(d2Fdudm) hessian_output -= compat.assemble_adjoint_value(dFdm_adj2) if isinstance(c, compat.ExpressionType): return [(hessian_output, W)] else: return hessian_output