def integrate(self): vector_over_time = list() N = self._function_over_time[0].N for function in self._function_over_time: assert function.N == N vector_over_time.append(function.vector()) integrated_vector = simps(vector_over_time, dx=self._time_step_size, axis=0) integrated_function = Function(N) integrated_function.vector()[:] = integrated_vector return integrated_function
class _ScipyImplicitEuler(object): def __init__(self, residual_eval, solution, solution_dot, bc_eval, jacobian_eval, set_time, problem_type): self.residual_eval = residual_eval self.solution = solution self.solution_dot = solution_dot self.solution_previous = Function(solution.vector().N) # equal to zero self.zero = Function(self.solution.vector().N) # equal to zero self.bc_eval = bc_eval self.jacobian_eval = jacobian_eval self.set_time = set_time self.problem_type = problem_type # Setup solver if problem_type == "linear": class _LinearSolver(LinearSolver): def __init__(self_, t): self.set_time(t) minus_solution_previous_over_dt = self.solution_previous minus_solution_previous_over_dt.vector()[:] /= - self._time_step_size lhs = self.jacobian_eval(t, self.zero, self.zero, 1./self._time_step_size) rhs = - self.residual_eval(t, self.zero, minus_solution_previous_over_dt) bcs_t = self.bc_eval(t) LinearSolver.__init__(self_, lhs, self.solution, rhs, bcs_t) self.solver_generator = _LinearSolver elif problem_type == "nonlinear": class _NonlinearSolver(NonlinearSolver): def __init__(self_, t): class _NonlinearProblemWrapper(NonlinearProblemWrapper): def __init__(self_): self.set_time(t) def _store_solution_and_solution_dot(self_, solution): self.solution.vector()[:] = solution.vector() self.solution_dot.vector()[:] = (solution.vector() - self.solution_previous.vector())/self._time_step_size def jacobian_eval(self_, solution): self_._store_solution_and_solution_dot(solution) return self.jacobian_eval(t, self.solution, self.solution_dot, 1./self._time_step_size) def residual_eval(self_, solution): self_._store_solution_and_solution_dot(solution) return self.residual_eval(t, self.solution, self.solution_dot) def bc_eval(self_): return self.bc_eval(t) NonlinearSolver.__init__(self_, _NonlinearProblemWrapper(), self.solution) self.solver_generator = _NonlinearSolver # Additional storage which will be setup by set_parameters self._final_time = None self._initial_time = 0. self._nonlinear_solver_parameters = None self._max_time_steps = None self._monitor = None self._report = None self._time_step_size = None def set_parameters(self, parameters): for (key, value) in parameters.items(): if key == "final_time": self._final_time = value elif key == "initial_time": self._initial_time = value elif key == "integrator_type": assert value == "beuler" elif key == "max_time_steps": self._max_time_steps = value elif key == "monitor": self._monitor = value elif key == "nonlinear_solver": self._nonlinear_solver_parameters = value elif key == "problem_type": assert value == self.problem_type elif key == "report": if value is True: def print_time(t): print("# t = {0:g}".format(t)) self._report = print_time else: self._report = None elif key == "time_step_size": self._time_step_size = value else: raise ValueError("Invalid paramater passed to _ScipyImplicitEuler object.") def solve(self): assert self._max_time_steps is not None or self._time_step_size is not None if self._time_step_size is not None: all_t = arange(self._initial_time, self._final_time + self._time_step_size, self._time_step_size) elif self._max_time_steps is not None: all_t = linspace(self._initial_time, self._final_time, num=self._max_time_steps+1) self._time_step_size = float(all_t[2] - all_t[1]) all_solutions = list() all_solutions.append(function_copy(self.solution)) all_solutions_dot = list() all_solutions_dot.append(function_copy(self.solution_dot)) self.solution_previous.vector()[:] = self.solution.vector() for t in all_t[1:]: if self._report is not None: self._report(t) solver = self.solver_generator(t) if self.problem_type == "nonlinear": if self._nonlinear_solver_parameters is not None: solver.set_parameters(self._nonlinear_solver_parameters) solver.solve() all_solutions.append(function_copy(self.solution)) self.solution_dot.vector()[:] = (all_solutions[-1].vector() - all_solutions[-2].vector())/self._time_step_size all_solutions_dot.append(function_copy(self.solution_dot)) self.solution_previous.vector()[:] = self.solution.vector() if self._monitor is not None: self._monitor(t, self.solution, self.solution_dot) return all_t, all_solutions, all_solutions_dot