def _compute_residual(self, finalize=False): LOG.debug("Computing Residual") self._print_step(1, None, self.state.current_level.initial.time_point, supremum_norm(self.state.current_level.initial.value), None, None) _full_integral = 0.0 self._recompute_rhs_for_level(self.state.current_level) for _step_index in range(0, len(self.state.current_level)): _step = self.state.current_level[_step_index] if not _step.integral_available: _step.integral = \ self.ml_provider \ .integrator(self.state.current_level_index) \ .evaluate(self.state.current_level.rhs, from_node=_step_index, target_node=_step_index + 1) _full_integral += _step.integral self._core.compute_residual(self.state, step=_step, integral=_full_integral) if finalize: # finalize this step (i.e. StepSolutionData.finalize()) _step.done() for _step_index in range(0, len(self.state.current_level)): _step = self.state.current_level[_step_index] if _step_index > 0: _previous_time = self.state.current_level[_step_index - 1].time_point else: _previous_time = self.state.current_level.initial.time_point _fas = _step.fas_correction if not self.state.current_iteration.on_finest_level else None _cc = _step.coarse_correction if not self.state.current_iteration.on_finest_level else None if problem_has_exact_solution(self.problem, self): self._print_step(_step_index + 2, _previous_time, _step.time_point, supremum_norm(_step.value), _step.solution.residual, _step.solution.error, _fas, _cc) else: self._print_step(_step_index + 2, _previous_time, _step.time_point, supremum_norm(_step.value), _step.solution.residual, None, _fas, _cc) self._print_sweep_end() if finalize: LOG.debug("Finalizing Level %d" % self.state.current_iteration.current_level_index) self.state.current_iteration.current_level.finalize()
def _value_to_numeric(val): if isinstance(val, np.ndarray): if val.size > 1 or val.dtype == np.complex: return supremum_norm(val) else: return val[0] elif isinstance(val, IDiagnosisValue): if val.value.shape != (1,): return supremum_norm(val) else: return val.value[0] else: return val
def _add_solution_plot(self, index): _res = np.zeros(len(self._states[index]) - 1) _red = np.zeros(len(self._states[index]) - 1) for i in range(1, len(self._states[index])): _res[i - 1] = supremum_norm(self._states[index][i].solution.residuals[-1].value) _red[i - 1] = supremum_norm(self._states[index].solution.solution_reduction(i)) if _res.min() < self.__residual_limits[0]: self.__residual_limits[0] = _res.min() if _res.max() > self.__residual_limits[1]: self.__residual_limits[1] = _res.max() if _red.min() < self.__reduction_limits[0]: self.__reduction_limits[0] = _red.min() if _red.max() > self.__reduction_limits[1]: self.__reduction_limits[1] = _red.max() plt.loglog(_res, _red, color=ReductionResidualPlotter._colors[index])
def _print_time_step(self, time_step, start, end, delta): _time_step = self._output_format(time_step, "int", width=3) _start = self._output_format(start, "float", width=6.3) _end = self._output_format(end, "float", width=6.3) _delta = self._output_format(delta, "float", width=6.3) LOG.info("%s |- %s %s %s %s" % (VERBOSITY_LVL2, _time_step, _start, _end, _delta)) LOG.info("%s | \\" % VERBOSITY_LVL3) self._print_step( 1, None, self.state.current_time_step.initial.time_point, supremum_norm(self.state.current_time_step.initial.solution.value), None, None, )
def compute_reduction(self, state): """Computes the reduction of the error and solution With respect to the supremum nomr of the given state's current iteration (see :py:attr:`.ISolverState.current_iteration` and :py:class:`.IIterationState`). In case no previous iteration is available, it immediatly returns. """ if not state.previous_iteration: # there is no previous iteration to compare with LOG.debug("Skipping computation of reduction: No previous iteration available.") return if state.current_iteration.final_step.solution.error: # error is given; computing reduction of it _previous_error = supremum_norm(state.previous_iteration.final_step.solution.error) _current_error = supremum_norm(state.current_iteration.final_step.solution.error) state.solution.set_error_reduction(state.current_iteration_index, abs((_previous_error - _current_error) / _previous_error * 100)) # computing reduction of solution _previous_solution = supremum_norm(state.previous_iteration.final_step.solution.value) _current_solution = supremum_norm(state.current_iteration.final_step.solution.value) state.solution.set_solution_reduction(state.current_iteration_index, abs((_previous_solution - _current_solution) / _previous_solution * 100))
def _check(self, operator, name, value): _value = supremum_norm(value) if isinstance(value, (IDiagnosisValue, np.ndarray)) else value if name in self._conditions and self._conditions[name] is not None: assert_condition(_value is not None, ValueError, message="'{:s}' is a termination condition but not available to check." .format(name[0].capitalize() + name[1:]), checking_obj=self) if operator == "min": if _value <= self._conditions[name]: LOG.debug("Minimum of {:s} reached: {:.2e} <= {:.2e}" .format(name, _value, self._conditions[name])) self._reason.append(name) elif operator == "max": if _value >= self._conditions[name]: LOG.debug("Maximum of {:s} exceeded: {:d} >= {:d}" .format(name, _value, self._conditions[name])) self._reason.append(name) else: raise ValueError("Given operator '{:s}' is invalid.".format(operator)) else: # $name is not a condition pass
def run(self, core, **kwargs): """Applies SDC solver to the initialized problem setup. Solves the given problem with the explicit SDC algorithm. Parameters ---------- core : :py:class:`.SdcSolverCore` core solver stepping method dt : :py:class:`float` width of the interval to work on; this is devided into the number of given time steps this solver has been initialized with See Also -------- :py:meth:`.IIterativeTimeSolver.run` : overridden method """ super(MlSdc, self).run(core, **kwargs) assert_named_argument('dt', kwargs, types=float, descriptor="Width of Interval", checking_obj=self) self._dt = kwargs['dt'] self._print_header() # start iterations # TODO: exact solution storage handling self.__exact[0] = self.problem.initial_value _has_work = True _previous_flag = Message.SolverFlag.none _current_flag = Message.SolverFlag.none __work_loop_count = 1 while _has_work: # LOG.debug("Work Loop: %d" % __work_loop_count) _previous_flag = _current_flag _current_flag = Message.SolverFlag.none # receive dedicated message _msg = self._communicator.receive(tag=(self.ml_provider.num_levels - 1)) if _msg.flag == Message.SolverFlag.failed: # previous solver failed # --> pass on the failure and abort _current_flag = Message.SolverFlag.failed _has_work = False # LOG.debug("Previous Solver Failed") else: if _msg.flag == Message.SolverFlag.time_adjusted: # the previous solver has adjusted its interval # --> we need to recompute our interval _current_flag = self._adjust_interval_width() # we don't immediately start the computation of the newly computed interval # but try to pass the new interval end to the next solver as soon as possible # (this should avoid throwing away useless computation) # LOG.debug("Previous Solver Adjusted Time") else: if _previous_flag in \ [Message.SolverFlag.none, Message.SolverFlag.converged, Message.SolverFlag.finished, Message.SolverFlag.time_adjusted]: # we just started or finished our previous interval # --> start a new interval _has_work = self._init_new_interval(_msg.time_point) if _has_work: # set initial values self.state.initial.value = _msg.value.copy() self.state.initial.solution.time_point = _msg.time_point self.state.initial.done() # LOG.debug("New Interval Initialized") # start logging output self._print_interval_header() # start global timing (per interval) self.timer.start() else: # LOG.debug("No New Interval Available") pass elif _previous_flag == Message.SolverFlag.iterating: # LOG.debug("Next Iteration") pass else: # LOG.warn("WARNING!!! Something went wrong here") pass if _has_work: # we are still on the same interval or have just successfully initialized a new interval # --> do the real computation # LOG.debug("Starting New Solver Main Loop") # initialize a new iteration state self.state.proceed() if _msg.time_point == self.state.initial.time_point: if _previous_flag == Message.SolverFlag.iterating: # LOG.debug("Updating initial value") # if the previous solver has a new initial value for us, we use it self.state.current_iteration.initial.value = _msg.value.copy() _current_flag = self._main_solver_loop() if _current_flag in \ [Message.SolverFlag.converged, Message.SolverFlag.finished, Message.SolverFlag.failed]: _log_msgs = {'': OrderedDict()} if self.state.last_iteration_index <= self.threshold.max_iterations: _group = 'Converged after %d iteration(s)' % (self.state.last_iteration_index + 1) _log_msgs[''][_group] = OrderedDict() _log_msgs[''][_group] = self.threshold.has_reached(log=True) _log_msgs[''][_group]['Final Residual'] = "{:.3e}"\ .format(supremum_norm(self.state.last_iteration.final_step.solution.residual)) _log_msgs[''][_group]['Solution Reduction'] = "{:.3e}"\ .format(supremum_norm(self.state.solution .solution_reduction(self.state.last_iteration_index))) if problem_has_exact_solution(self.problem, self): _log_msgs[''][_group]['Error Reduction'] = "{:.3e}"\ .format(supremum_norm(self.state.solution .error_reduction(self.state.last_iteration_index))) else: warnings.warn("{}: Did not converged: {:s}".format(self._core.name, self.problem)) _group = "FAILED: After maximum of {:d} iteration(s)"\ .format(self.state.last_iteration_index + 1) _log_msgs[''][_group] = OrderedDict() _log_msgs[''][_group]['Final Residual'] = "{:.3e}"\ .format(supremum_norm(self.state.last_iteration.final_step.solution.residual)) _log_msgs[''][_group]['Solution Reduction'] = "{:.3e}"\ .format(supremum_norm(self.state.solution .solution_reduction(self.state.last_iteration_index))) if problem_has_exact_solution(self.problem, self): _log_msgs[''][_group]['Error Reduction'] = "{:.3e}"\ .format(supremum_norm(self.state.solution .error_reduction(self.state.last_iteration_index))) LOG.warn(" {} Failed: Maximum number iterations reached without convergence." .format(self._core.name)) print_logging_message_tree(_log_msgs) elif _previous_flag in [Message.SolverFlag.converged, Message.SolverFlag.finished]: # LOG.debug("Solver Finished.") self.timer.stop() self._print_footer() else: # something went wrong # --> we failed # LOG.warn("Solver failed.") _current_flag = Message.SolverFlag.failed self._communicator.send(value=self.state.current_iteration.finest_level.final_step.value, time_point=self.state.current_iteration.finest_level.final_step.time_point, flag=_current_flag) __work_loop_count += 1 # end while:has_work is None # LOG.debug("Solver Main Loop Done") return [_s.solution for _s in self._states]
def test_supremums_norm(self): self.assertEqual(supremum_norm(self._value), 3.0) self.assertEqual(supremum_norm(self._value.value), 3.0)
def _value_to_numeric(val): if isinstance(val, (np.ndarray, IDiagnosisValue)): return supremum_norm(val) else: return val
def _time_step(self): self.state.current_time_step.delta_time_step = self._deltas["t"] for _step in range(0, len(self.state.current_time_step)): _node_index = self.state.current_time_step_index * (self.num_nodes - 1) + _step self.state.current_time_step[_step].delta_tau = self._deltas["n"][_node_index] self.state.current_time_step[_step].solution.time_point = self.__time_points["nodes"][ self.state.current_time_step_index ][_step + 1] self._print_time_step( self.state.current_time_step_index + 1, self.state.current_time_step.initial.time_point, self.state.current_time_step.last.time_point, self.state.current_time_step.delta_time_step, ) # for classic SDC compute integral _integral = 0.0 _integrate_values = None if self.classic: if not self.state.current_time_step.initial.rhs_evaluated: self.state.current_time_step.initial.rhs = self.problem.evaluate_wrt_time( self.state.current_time_step.initial.time_point, self.state.current_time_step.initial.value ) _integrate_values = np.array([self.state.current_time_step.initial.rhs], dtype=self.problem.numeric_type) for _step_index in range(0, len(self.state.current_time_step)): if self.state.is_first_iteration: _integrate_values = np.append( _integrate_values, np.array([self.state.current_time_step.initial.rhs], dtype=self.problem.numeric_type), axis=0, ) else: _step = self.state.previous_iteration[self.state.current_time_step_index][_step_index] if not _step.rhs_evaluated: _step.rhs = self.problem.evaluate_wrt_time(_step.time_point, _step.value) _integrate_values = np.append( _integrate_values, np.array([_step.rhs], dtype=self.problem.numeric_type), axis=0 ) assert_condition( _integrate_values.shape[0] == self.num_nodes, ValueError, message="Number of integration values not correct: {:d} != {:d}".format( _integrate_values.shape[0], self.num_nodes ), checking_obj=self, ) _full_integral = 0.0 # do the actual SDC steps of this SDC sweep for _step_index in range(0, len(self.state.current_time_step)): _current_step = self.state.current_time_step[_step_index] if self.classic: _integral = self._integrator.evaluate( _integrate_values, from_node=_step_index, target_node=_step_index + 1 ) # we successively compute the full integral, which is used for the residual at the end _full_integral += _integral _current_step.integral = _integral.copy() # do the SDC step of this sweep self._sdc_step() if self.state.current_step_index < len(self.state.current_time_step) - 1: self.state.current_time_step.proceed() del _integrate_values # compute residual and print step details for _step_index in range(0, len(self.state.current_time_step)): _step = self.state.current_time_step[_step_index] self._core.compute_residual(self.state, step=_step, integral=_full_integral) # finalize this step (i.e. StepSolutionData.finalize()) _step.done() if _step_index > 0: _previous_time = self.state.current_time_step[_step_index - 1].time_point else: _previous_time = self.state.current_time_step.initial.time_point if problem_has_exact_solution(self.problem, self): self._print_step( _step_index + 2, _previous_time, _step.time_point, supremum_norm(_step.value), _step.solution.residual, _step.solution.error, ) else: self._print_step( _step_index + 2, _previous_time, _step.time_point, supremum_norm(_step.value), _step.solution.residual, None, ) self._print_time_step_end() # finalizing the current time step (i.e. TrajectorySolutionData.finalize) self.state.current_time_step.finalize()
def plot(self, *args, **kwargs): """Plots the solution and optional also the error for each iteration. Parameters ---------- solver : :py:class:`.IIterativeTimeSolver` solver instance used to calculate the solution state : :py:class:`.ISolverState` state containing information to plot errplot : :py:class:`bool` *(optional)* if given and :py:class:`True` also plots the errors for each iteration found in the solution residualplot : :py:class:`bool` *(optional)* if given and :py:class:`True` also plots the residual for each iteration found in the solution Raises ------ ValueError * if ``solver`` not given and not an :py:class:`.IIterativeTimeSolver` * if ``state`` not given and not an :py:class:`.ISolverState` """ super(SingleSolutionPlotter, self).plot(args, **kwargs) assert_named_argument('solver', kwargs, types=IIterativeTimeSolver, descriptor="Solver", checking_obj=self) assert_named_argument('state', kwargs, types=ISolverState, descriptor="State must be given", checking_obj=self) self._solver = kwargs['solver'] self._state = kwargs['state'] self._nodes = self._state.first.time_points _subplots = 1 _curr_subplot = 0 if 'errorplot' in kwargs and kwargs['errorplot']: _subplots += 1 self._errplot = True if 'residualplot' in kwargs and kwargs['residualplot']: _subplots += 1 self._residualplot = True if self._solver.problem.time_start != self._nodes[0]: self._nodes = np.concatenate(([self._solver.problem.time_start], self._nodes)) if self._solver.problem.time_end != self._nodes[-1]: self._nodes = np.concatenate((self._nodes, [self._solver.problem.time_end])) if self._errplot or self._residualplot: plt.suptitle(r"after {:d} iterations; overall reduction: {:.2e}" .format(len(self._state), supremum_norm(self._state.solution .solution_reduction(self._state.last_iteration_index)))) _curr_subplot += 1 plt.subplot(_subplots, 1, _curr_subplot) self._final_solution() plt.title(self._solver.problem.__str__()) if self._errplot: _curr_subplot += 1 plt.subplot(3, 1, _curr_subplot) self._error_plot() if self._residualplot: _curr_subplot += 1 plt.subplot(3, 1, _curr_subplot) self._residual_plot() if self._file_name is not None: fig = plt.gcf() fig.set_dpi(300) fig.set_size_inches((15., 15.)) LOG.debug("Plotting figure with size (w,h) {:s} inches and {:d} DPI." .format(fig.get_size_inches(), fig.get_dpi())) fig.savefig(self._file_name) if is_interactive(): plt.show(block=True) else: plt.close('all')