def __compute_state_equations(self): """Calculates the weak form of the state equation for the use with fenics. Returns ------- None """ if self.state_is_linear: self.state_eq_forms = [ replace( self.state_forms[i], { self.states[i]: self.trial_functions_state[i], self.adjoints[i]: self.test_functions_state[i] }) for i in range(self.state_dim) ] else: self.state_eq_forms = [ fenics.derivative(self.state_forms[i], self.adjoints[i], self.test_functions_state[i]) for i in range(self.state_dim) ] if self.state_is_picard: self.state_picard_forms = [ fenics.derivative(self.state_forms[i], self.adjoints[i], self.test_functions_state[i]) for i in range(self.state_dim) ] if self.state_is_linear: self.state_eq_forms_lhs = [] self.state_eq_forms_rhs = [] for i in range(self.state_dim): try: a, L = fenics.system(self.state_eq_forms[i]) except UFLException: raise CashocsException( 'The state system could not be transferred to a linear system.\n' 'Perhaps you specified that the system is linear, allthough it is not.\n' 'In your config, in the StateEquation section, try using is_linear = False.' ) self.state_eq_forms_lhs.append(a) if L.empty(): zero_form = fenics.inner( fenics.Constant( np.zeros(self.test_functions_state[i].ufl_shape)), self.test_functions_state[i]) * self.dx self.state_eq_forms_rhs.append(zero_form) else: self.state_eq_forms_rhs.append(L)
def __compute_adjoint_equations(self): """Calculates the weak form of the adjoint equation for use with fenics. Returns ------- None """ # Use replace -> derivative to speed up computations self.lagrangian_temp_forms = [ replace(self.lagrangian.lagrangian_form, {self.adjoints[i]: self.trial_functions_adjoint[i]}) for i in range(self.state_dim) ] if self.state_is_picard: self.adjoint_picard_forms = [ fenics.derivative(self.lagrangian.lagrangian_form, self.states[i], self.test_functions_adjoint[i]) for i in range(self.state_dim) ] self.adjoint_eq_forms = [ fenics.derivative(self.lagrangian_temp_forms[i], self.states[i], self.test_functions_adjoint[i]) for i in range(self.state_dim) ] self.adjoint_eq_lhs = [] self.adjoint_eq_rhs = [] for i in range(self.state_dim): a, L = fenics.system(self.adjoint_eq_forms[i]) self.adjoint_eq_lhs.append(a) if L.empty(): zero_form = fenics.inner( fenics.Constant( np.zeros(self.test_functions_adjoint[i].ufl_shape)), self.test_functions_adjoint[i]) * self.dx self.adjoint_eq_rhs.append(zero_form) else: self.adjoint_eq_rhs.append(L) # Compute the adjoint boundary conditions if self.state_adjoint_equal_spaces: self.bcs_list_ad = [[ fenics.DirichletBC(bc) for bc in self.bcs_list[i] ] for i in range(self.state_dim)] [[bc.homogenize() for bc in self.bcs_list_ad[i]] for i in range(self.state_dim)] else: def get_subdx(V, idx, ls): if V.id() == idx: return ls if V.num_sub_spaces() > 1: for i in range(V.num_sub_spaces()): ans = get_subdx(V.sub(i), idx, ls + [i]) if ans is not None: return ans else: return None self.bcs_list_ad = [[1 for bc in range(len(self.bcs_list[i]))] for i in range(self.state_dim)] for i in range(self.state_dim): for j, bc in enumerate(self.bcs_list[i]): idx = bc.function_space().id() subdx = get_subdx(self.state_spaces[i], idx, ls=[]) W = self.adjoint_spaces[i] for num in subdx: W = W.sub(num) shape = W.ufl_element().value_shape() try: if shape == (): self.bcs_list_ad[i][j] = fenics.DirichletBC( W, fenics.Constant(0), bc.domain_args[0], bc.domain_args[1]) else: self.bcs_list_ad[i][j] = fenics.DirichletBC( W, fenics.Constant([0] * W.ufl_element().value_size()), bc.domain_args[0], bc.domain_args[1]) except AttributeError: if shape == (): self.bcs_list_ad[i][j] = fenics.DirichletBC( W, fenics.Constant(0), bc.sub_domain) else: self.bcs_list_ad[i][j] = fenics.DirichletBC( W, fenics.Constant([0] * W.ufl_element().value_size()), bc.sub_domain)
def supply_adjoint_forms(self, adjoint_forms, adjoint_bcs_list): """Overrides the computed weak forms of the adjoint system. This allows the user to specify their own weak forms of the problems and to use cashocs merely as a solver for solving the optimization problems. Parameters ---------- adjoint_forms : ufl.form.Form or list[ufl.form.Form] The UFL forms of the adjoint system(s). adjoint_bcs_list : list[dolfin.fem.dirichletbc.DirichletBC] or list[list[dolfin.fem.dirichletbc.DirichletBC]] or dolfin.fem.dirichletbc.DirichletBC or None The list of Dirichlet boundary conditions for the adjoint system(s). Returns ------- None """ try: if type(adjoint_forms) == list and len(adjoint_forms) > 0: for i in range(len(adjoint_forms)): if adjoint_forms[i].__module__=='ufl.form' and type(adjoint_forms[i]).__name__=='Form': pass else: raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_adjoint_forms', 'adjoint_forms', 'adjoint_forms have to be ufl forms') mod_forms = adjoint_forms elif adjoint_forms.__module__ == 'ufl.form' and type(adjoint_forms).__name__ == 'Form': mod_forms = [adjoint_forms] else: raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_adjoint_forms', 'adjoint_forms', 'adjoint_forms have to be ufl forms') except: raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_adjoint_forms', 'adjoint_forms', 'adjoint_forms have to be ufl forms') try: if adjoint_bcs_list == [] or adjoint_bcs_list is None: mod_bcs_list = [] for i in range(self.state_dim): mod_bcs_list.append([]) elif type(adjoint_bcs_list) == list and len(adjoint_bcs_list) > 0: if type(adjoint_bcs_list[0]) == list: for i in range(len(adjoint_bcs_list)): if type(adjoint_bcs_list[i]) == list: pass else: raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_adjoint_forms', 'adjoint_bcs_list', 'adjoint_bcs_list has inconsistent types.') mod_bcs_list = adjoint_bcs_list elif adjoint_bcs_list[0].__module__ == 'dolfin.fem.dirichletbc' and type(adjoint_bcs_list[0]).__name__ == 'DirichletBC': for i in range(len(adjoint_bcs_list)): if adjoint_bcs_list[i].__module__=='dolfin.fem.dirichletbc' and type(adjoint_bcs_list[i]).__name__=='DirichletBC': pass else: raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply adjoint_forms', 'adjoint_bcs_list', 'adjoint_bcs_list has inconsistent types.') mod_bcs_list = [adjoint_bcs_list] elif adjoint_bcs_list.__module__ == 'dolfin.fem.dirichletbc' and type(adjoint_bcs_list).__name__ == 'DirichletBC': mod_bcs_list = [[adjoint_bcs_list]] else: raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_adjoint_forms', 'adjoint_bcs_list', 'Type of adjoint_bcs_list is wrong.') except: raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_adjoint_forms', 'adjoint_bcs_list', 'Type of adjoint_bcs_list is wrong.') if not len(mod_forms) == self.form_handler.state_dim: raise InputError('cashocs.optimization_problem.OptimizationProblem.supply_adjoint_forms', 'adjoint_forms', 'Length of adjoint_forms does not match') if not len(mod_bcs_list) == self.form_handler.state_dim: raise InputError('cashocs.optimization_problem.OptimizationProblem.supply_adjoint_forms', 'adjoint_bcs_list', 'Length of adjoint_bcs_list does not match') for idx, form in enumerate(mod_forms): if len(form.arguments()) == 2: raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_adjoint_forms', 'adjoint_forms', 'Do not use TrialFunction for the adjoints, but the actual Function you passed to th OptimalControlProblem.') elif len(form.arguments()) == 0: raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_adjoint_forms', 'adjoint_forms', 'The specified adjoint_forms must include a TestFunction object.') if not form.arguments()[0].ufl_function_space() == self.form_handler.adjoint_spaces[idx]: raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_adjoint_forms', 'adjoint_forms', 'The TestFunction has to be chosen from the same space as the corresponding adjoint.') self.form_handler.adjoint_picard_forms = mod_forms self.form_handler.bcs_list_ad = mod_bcs_list # replace the adjoint function by a TrialFunction for internal use repl_forms = [replace(mod_forms[i], {self.adjoints[i] : self.form_handler.trial_functions_adjoint[i]}) for i in range(self.state_dim)] self.form_handler.adjoint_eq_forms = repl_forms self.form_handler.adjoint_eq_lhs = [] self.form_handler.adjoint_eq_rhs = [] for i in range(self.state_dim): a, L = fenics.system(self.form_handler.adjoint_eq_forms[i]) self.form_handler.adjoint_eq_lhs.append(a) if L.empty(): zero_form = fenics.inner(fenics.Constant(np.zeros(self.form_handler.test_functions_adjoint[i].ufl_shape)), self.form_handler.test_functions_adjoint[i])*self.form_handler.dx self.form_handler.adjoint_eq_rhs.append(zero_form) else: self.form_handler.adjoint_eq_rhs.append(L) self.has_custom_adjoint = True