Пример #1
0
    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()
Пример #2
0
 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
Пример #3
0
    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])
Пример #4
0
 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,
     )
Пример #5
0
    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))
Пример #6
0
    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
Пример #7
0
    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]
Пример #8
0
 def test_supremums_norm(self):
     self.assertEqual(supremum_norm(self._value), 3.0)
     self.assertEqual(supremum_norm(self._value.value), 3.0)
Пример #9
0
 def _value_to_numeric(val):
     if isinstance(val, (np.ndarray, IDiagnosisValue)):
         return supremum_norm(val)
     else:
         return val
Пример #10
0
    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()
Пример #11
0
    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')