def problem_has_exact_solution(problem, checking_obj=None):
    """Convenience accessor for exact solution.

    Parameters
    ----------
    problem : :py:class:`.IProblem`
        The problem to check for an exact solution function.
    checking_obj : object
        *(optional)*
        The object calling this function for a meaningful error message.
        For debugging purposes only.

    Returns
    -------
    has_exact_solution : :py:class:`bool`
        :py:class:`True` if exact solution was given, :py:class:`False` otherwise

    Raises
    ------
    ValueError :
        If the given problem is not an instance of :py:class:`.IProblem`.
    """
    assert_is_instance(
        problem, IProblem, message="It needs to be a problem to have an exact solution.", checking_obj=checking_obj
    )
    return isinstance(problem, HasExactSolutionMixin)
 def time_interval(self, value):
     assert_is_instance(value, np.ndarray, descriptor="Time Interval", checking_obj=self)
     assert_condition(value.size == 2, ValueError,
                      message="Time Interval must have two values: NOT %d" % value.size)
     self.validate_time_interval(start=value[0], end=value[1])
     self.time_start = value[0]
     self.time_end = value[1]
Beispiel #3
0
    def __init__(self, restriction_stencil, decrease_in_points=None, center=None):
        assert_is_instance(restriction_stencil, np.ndarray, "Not an ndarray")
        self.rst_stencil = Stencil(restriction_stencil, center)


        if decrease_in_points is None:
            self.dip = np.asarray(self.rst_stencil.shape) - 1
        elif isinstance(decrease_in_points, np.ndarray) and \
                        decrease_in_points.ndim == restriction_stencil.ndim:
            self.dip = decrease_in_points
        elif isinstance(decrease_in_points, int):
            self.dip = np.asarray([decrease_in_points]*restriction_stencil.ndim)
        else:
            raise ValueError("Wrong decrease in points")
        self.dim = restriction_stencil.ndim

        if self.dim == 1:
            self.eval = self.evalA_1D
        elif self.dim == 2:
            self.eval = self.evalA_2D
        elif self.dim == 3:
            self.eval = self.evalA_3D
        else:
            raise NotImplementedError("More than 3 dimensions " +
                                      "are not implemented")
    def __init__(self, *args, **kwargs):
        """
        Parameters
        ----------
        exact_function : :py:class:`callable`
            *(optional)*
            If given initializes the problem with the exact solution function.
        """
        assert_is_instance(
            self,
            IProblem,
            descriptor="Problem needs to be a IProblem first: NOT %s" % class_name(self),
            checking_obj=self,
        )
        self._exact_function = None
        if "exact_function" in kwargs:
            self.exact_function = kwargs["exact_function"]

        self._strings["exact"] = None
        if "strings" in kwargs:
            if "exact" in kwargs["strings"]:
                assert_is_instance(
                    kwargs["strings"]["exact"],
                    str,
                    descriptor="String representation of Exact Function",
                    checking_obj=self,
                )
                self._strings["exact"] = kwargs["strings"]["exact"]
Beispiel #5
0
    def add_level_transition(self, transitioner, coarse_level, fine_level):
        """Adds specialized level transitioner for specified levels.

        Parameters
        ----------
        transitioner : :py:class:`.ILevelTransitionProvider`
            Special level transitioner for specified prolongation and restringation between given coarse and fine level.

        coarse_level : :py:class:`int`
            Coarse level of the transitioner.

        fine_level : :py:class:`int`
            Fine level of the transitioner.

        Raises
        ------
        ValueError
            if ``transitioner`` is not an :py:class:`.ILevelTransitionProvider`
        """
        assert_is_instance(transitioner, ILevelTransitionProvider, descriptor="Level Transitioner", checking_obj=self)

        # extend/initialize level_transition_provider map if necessary
        if coarse_level not in self._level_transitioners:
            self._level_transitioners[coarse_level] = {}

        self._level_transitioners[coarse_level][fine_level] = transitioner
Beispiel #6
0
    def __init__(self, *args, **kwargs):
        super(HeatEquation, self).__init__(*args, **kwargs)

        # HasExactSolutionMixin.__init__(self, *args, **kwargs)

        self._thermal_diffusivity = kwargs.get('thermal_diffusivity', 1.0)

        if self.time_start is None:
            self.time_start = 0.0
        if self.time_end is None:
            self.time_end = 1.0
        if self.initial_value is None:
            self.initial_value = np.zeros(self.dim_for_time_solver)

        if isinstance(self.thermal_diffusivity, complex):
            self.numeric_type = np.complex

        self._mg_stencil = kwargs.get('mg_stencil')
        self._mg_level = kwargs.get('mg_level')
        self._direct_solvers = {}

        if kwargs.get('delta_times_for_time_levels') is not None and self._mg_level is not None:
            assert_is_instance(kwargs['delta_times_for_time_levels'], (list, np.ndarray),
                               descriptor="Delta Times for Time Levels", checking_obj=self)
            for time_level in kwargs['delta_times_for_time_levels']:
                assert_is_instance(kwargs['delta_times_for_time_levels'][time_level], (list, np.ndarray),
                                   descriptor="Delta Times for Time Level %d" % time_level, checking_obj=self)
                for delta_time in kwargs['delta_times_for_time_levels'][time_level]:
                    self.initialize_direct_space_solver(time_level, delta_time, kwargs['mg_level'])
    def write_buffer(self, tag=None, **kwargs):
        """Writes data into this communicator's buffer

        Parameters
        ----------
        value :
            data values to be send to the next solver
        time_point : :py:class:`float`
            time point of the data values
        flag : :py:class:`.Message.SolverFlag`
            message flag

        Raises
        ------
        ValueError

            * if no arguments are given
            * if ``time_point`` is not a :py:class:`float`
        """
        assert_condition(len(kwargs) > 0, ValueError, "At least one argument must be given.", self)

        if tag not in self._buffer:
            self._buffer[tag] = Message()
            self.write_buffer(tag=tag, **kwargs)

        if "value" in kwargs:
            self._buffer[tag].value = deepcopy(kwargs["value"])

        if "time_point" in kwargs:
            assert_is_instance(kwargs["time_point"], float, descriptor="Time Point", checking_obj=self)
            self._buffer[tag].time_point = deepcopy(kwargs["time_point"])

        if "flag" in kwargs:
            self._buffer[tag].flag = deepcopy(kwargs["flag"])
Beispiel #8
0
    def __init__(self, stencil_list, center=None, *args, **kwargs):
        """init

        """
        # in the case of just one stencil
        if isinstance(stencil_list, np.ndarray) and stencil_list.ndim == 1:
            self.mode = "own"
            self.increase_of_points = 2
            self.stencil_list = []
            self.stencil_list.append(stencil_list)
            self.center = []
            if center is None:
                self.center.append(np.floor(np.asarray(self.stencil[0].shape)*0.5))
            elif isinstance(center, int) and center < self.stencil[0].size:
                self.center.append(center)
            else:
                raise ValueError("Wrong argument")
        # now the case of a stencil set
        elif isinstance(stencil_list, list):
            # check if each one is a nd.array
            for stencil in stencil_list:
                assert_is_instance(stencil, Stencil,
                                   "not real stencil", self)
            # each stencil
                self.mode = "list"
                self.stencil_list = stencil_list
                self.increase_of_points = len(stencil_list)
        if self.mode == "own":
            self.eval = self.eval_own
        elif self.mode == "list":
            self.eval = self.eval_list
        else:
            raise RuntimeError("Something went terribly wrong")
        super().__init__(*args, **kwargs)
def problem_has_direct_implicit(problem, checking_obj=None):
    """Convenience checker for existence of a direct implicit formulation of a problem.

    Parameters
    ----------
    problem : :py:class:`.IProblem`
        The problem to check for a direct implicit formulation.
    checking_obj : :py:class:`object`
        *(optional)*
        The object calling this function for a meaningful error message.
        For debugging purposes only.

    Returns
    -------
    has_direct_impl : :py:class:`bool`
        :py:class:`True` if exact solution was given, :py:class:`False` otherwise

    Raises
    ------
    ValueError :
        If the given problem is not an instance of :py:class:`.IProblem`.
    """
    assert_is_instance(problem, IProblem,
                       message="It needs to be a problem to have a direct implicit formula.", checking_obj=checking_obj)
    return isinstance(problem, HasDirectImplicitMixin)
Beispiel #10
0
    def evaluate(self, data, **kwargs):
        """Applies this integrator to given data in specified time interval.

        Parameters
        ----------
        data : :py:class:`numpy.ndarray`
            Data vector of the values at given time points.
            Its length must equal the number of integration nodes.
        time_start : :py:class:`float`
            *(optional)*
            Begining of the time interval to integrate over.
        time_end : :py:class:`float`
            *(optional)*
            End of the time interval to integrate over.

        Raises
        ------
        ValueError :

            * if ``data`` is not a :py:class:`numpy.ndarray`
            * if either ``time_start`` or ``time_end`` are not given
            * if ``time_start`` is larger or equals ``time_end``
        """
        assert_is_instance(data, np.ndarray, descriptor="Data to integrate", checking_obj=self)
        assert_condition("time_start" in kwargs or "time_end" in kwargs,
                         ValueError, message="Either start or end of time interval need to be given.",
                         checking_obj=self)
        assert_condition(kwargs["time_start"] < kwargs["time_end"],
                         ValueError,
                         message="Time interval need to be non-zero positive: [{:f}, {:f}]"
                                 .format(kwargs["time_start"], kwargs["time_end"]),
                         checking_obj=self)
    def add_coefficient(self, coefficient, power):
        """Adds or sets the coefficient :math:`c` of :math:`cx^p` for a specific :math:`p`.

        The polynomial gets automatically extended to hold the new coefficient in case it didn't included the specified
        power previously.
        Unset, but skipped powers have a coefficient of zero by default.

        Parameters
        ----------
        coefficient : :py:class:`float`
            Coefficient :math:`c` of :math:`cx^p`.
        power : :py:class:`int`
             Power :math:`p` of :math:`cx^p`.

        Examples
        --------
        >>> polyWeights = PolynomialWeightFunction()
        >>> # To set the coefficient of x^3 to 3.14 use:
        >>> polyWeights.add_coefficient(3.14, 3)
        >>> # Similar, to set the constant coefficient 42, e.i. 42*x^0, use:
        >>> polyWeights.add_coefficient(42, 0)
        """
        assert_is_instance(power, int, descriptor="Power", checking_obj=self)
        assert_condition(power >= 0, ValueError,
                         message="Power must be zero or positive: {:d}".format(power), checking_obj=self)

        if self._coefficients.size <= power + 1:
            self._coefficients = np.resize(self._coefficients, (power + 1))

        self._coefficients[power] = coefficient
Beispiel #12
0
 def value(self, value):
     assert_condition(not self.finalized, AttributeError,
                      message="Cannot change this solution data storage any more.", checking_obj=self)
     assert_is_instance(value, np.ndarray, descriptor="Values", checking_obj=self)
     self._dim = value.shape
     self._numeric_type = value.dtype
     self._data = value
    def construct_space_tensor(self, number_of_points_list, stencil=None):
        """Constructs the Spacetensor which is important for the evaluation in the case of Dirichlet boundary conditions

        Parameters
        ----------
        number_of_points_list : :py:class:`int` or :py:class:`numpy.ndarray`
            Number of points which will be distributed equiv-spaced on the grid
        """
        if isinstance(number_of_points_list, (int, float, complex)):
            assert_is_instance(stencil, Stencil, descriptor="Stencil", checking_obj=self)
            npoints = int(number_of_points_list)
            # LOG.debug("Your number %s was modified to %s" % (number_of_points_list, npoints))
            assert_condition(npoints > max(stencil.arr.shape), ValueError,
                             message="Not enough points for the stencil", checking_obj=self)
            npoints = np.asarray([npoints] * len(self.spacial_dim))
        elif isinstance(number_of_points_list, np.ndarray):
            assert_condition(len(number_of_points_list.shape) == 1 and number_of_points_list.size == len(self.spacial_dim),
                             ValueError, message="The number_of_points list is wrong", checking_obj=self)
            npoints = np.floor(number_of_points_list)
        else:
            raise ValueError("Wrong number of points list")

        # first we assign the memory using numpy
        # spt(npoints,dim)
        self._act_npoints = npoints
        lspc = []
        for i in range(len(self.spacial_dim)):
            lspc.append(np.linspace(self._geometry[i, 0], self._geometry[i, 1], npoints[i]))
        if len(self.spacial_dim) > 1:
            space_tensor = np.asarray(np.meshgrid(*lspc))
        else:
            space_tensor = np.linspace(self._geometry[0, 0], self._geometry[0, 1], npoints)

        return space_tensor
Beispiel #14
0
def find_root(fun, x0, method="hybr"):
    """Wrapper around SciPy's generic root finding algorithm to support complex numbers.

    SciPy's generic root finding algorithm (``scipy.optimize.root``) is not able to deal with functions returning
    and/or accepting arrays with complex numbers.

    This wrapped call will first convert all arrays of complex numbers into arrays of floats while splitting each
    complex number up into two floats.

    Parameters
    ----------
    fun : :py:class:`callable`
        Complex function to find the root of

    x0 : :py:class:`numpy.ndarray`
        Initial guess.

    method : :py:class:`str`
        Root finding method to be used.
        See ``scipy.optimize.root`` for details.

    Returns
    -------
    Same solution object as ``scipy.optimize.root`` but with ``x`` being converted back including complex numbers.

    Examples
    --------
        from pypint.plugins.implicit_solvers.find_root import find_root
        import numpy
        fun = lambda x: (-1.0 + 1.0j) * x
        sol = find_root(fun, numpy.array([0.0]))
    """
    assert_is_instance(x0, np.ndarray, descriptor="Initial Guess")
    assert_is_callable(fun, descriptor="Function to find root of")
    assert_is_instance(method, str, descriptor="Root finding method")

    _value_map = {}
    _transformed_size = 0
    _transform_necessary = False
    for i in range(0, x0.size):
        if isinstance(x0[i], complex):
            _value_map[i] = [_transformed_size, _transformed_size + 1]
            _transformed_size += 2
            _transform_necessary = True
        else:
            _value_map[i] = [_transformed_size]
            _transformed_size += 1

    if _transform_necessary:
        _wrapped_func = \
            lambda x_next: _transform_to_real(fun(_transform_to_complex(x_next, _value_map)),
                                              _value_map, _transformed_size)
        sol = root(fun=_wrapped_func, x0=_transform_to_real(x0, _value_map, _transformed_size), method=method)
    else:
        sol = root(fun=fun, x0=x0, method=method)

    if sol.success and _transform_necessary:
        sol.x = _transform_to_complex(sol.x, _value_map)
    return sol
Beispiel #15
0
 def implicit_solve(self, next_x, func, method="unused", **kwargs):
     """A solver for the implicit equations.
     """
     assert_is_instance(next_x, np.ndarray, descriptor="Initial Guess", checking_obj=self)
     assert_is_callable(func, descriptor="Function of RHS for Implicit Solver", checking_obj=self)
     sol = scop.newton_krylov(func, next_x.reshape(-1))
     assert_is_instance(sol, np.ndarray, descriptor="Solution", checking_obj=self)
     return sol.reshape(self.dim_for_time_solver)
Beispiel #16
0
    def _init_new_interval(self, start):
        """Initializes a new work interval

        Parameters
        ----------
        start : :py:class:`float`
            start point of new interval

        Returns
        -------
        has_work : :py:class:`bool`
            :py:class:`True` if new interval have been initialized;
            :py:class:`False` if no new interval have been initialized (i.e. new interval end would exceed end of time
            given by problem)
        """
        assert_is_instance(start, float, descriptor="Time Point", checking_obj=self)

        if start + self._dt > self.problem.time_end:
            return False

        if self.state and start == self.state.initial.time_point:
            return False

        self._init_new_state()

        # set width of current interval
        self.state.delta_interval = self._dt

        # compute time step and node distances
        self._deltas["t"] = self.state.delta_interval / self.num_time_steps  # width of a single time step (equidistant)

        # start time points of time steps
        self.__time_points["steps"] = np.linspace(start, start + self._dt, self.num_time_steps + 1)

        # initialize and transform integrator for time step width
        self._integrator.init(
            self.__nodes_type,
            self.__num_nodes,
            self.__weights_type,
            interval=np.array([self.__time_points["steps"][0], self.__time_points["steps"][1]], dtype=np.float),
        )

        self.__time_points["nodes"] = np.zeros((self.num_time_steps, self.num_nodes), dtype=np.float)
        _deltas_n = np.zeros(self.num_time_steps * (self.num_nodes - 1) + 1)

        # copy the node provider so we do not alter the integrator's one
        _nodes = deepcopy(self._integrator.nodes_type)
        for _t in range(0, self.num_time_steps):
            # transform Nodes (copy) onto new time step for retrieving actual integration nodes
            _nodes.interval = np.array([self.__time_points["steps"][_t], self.__time_points["steps"][_t + 1]])
            self.__time_points["nodes"][_t] = _nodes.nodes.copy()
            for _n in range(0, self.num_nodes - 1):
                _i = _t * (self.num_nodes - 1) + _n
                _deltas_n[_i + 1] = _nodes.nodes[_n + 1] - _nodes.nodes[_n]
        self._deltas["n"] = _deltas_n[1:].copy()

        return True
Beispiel #17
0
    def run(self, state, **kwargs):
        """Apply the solver core to the current state

        Parameters
        ----------
        state : :py:class:`.ISolverState`
            Current state of the solver.
        """
        assert_is_instance(state, ISolverState, descriptor="Solver's State", checking_obj=self)
Beispiel #18
0
    def compute_error(self, state, **kwargs):
        """Computes the error of the current state

        Parameters
        ----------
        state : :py:class:`.ISolverState`
            Current state of the solver.
        """
        assert_is_instance(state, ISolverState, descriptor="Solver's State", checking_obj=self)
Beispiel #19
0
 def __lt__(self, other):
     assert_is_instance(other, StepSolutionData,
                        message="Can not compare StepSolutionData with {}".format(class_name(other)),
                        checking_obj=self)
     return (
         self.dim == other.dim
         and self.numeric_type == other.numeric_type
         and self.time_point < other.time_point
     )
Beispiel #20
0
 def initial_value(self, initial_value):
     assert_is_instance(initial_value, np.ndarray, descriptor="Initial Value", checking_obj=self)
     assert_condition(
         initial_value.shape == self.dim_for_time_solver,
         ValueError,
         message="Initial Values shape must match problem DOFs: %s != %s"
         % (initial_value.shape, self.dim_for_time_solver),
         checking_obj=self,
     )
     self._initial_value = initial_value
Beispiel #21
0
    def __init__(self, *args, **kwargs):
        self._n = kwargs.get('n')
        self._m = 2*self._n + 1
        kwargs.update({"dim": (self._m, self._m, 1)})

        super(AvilesGiga, self).__init__(*args, **kwargs)

        # HasDirectImplicitMixin.__init__(self, *args, **kwargs)

        self._epsilon = kwargs.get('epsilon', 1.0)

        lspc = np.linspace(0, np.pi, self._m)
        x = np.meshgrid(lspc, lspc)
        if self.time_start is None:
            self.time_start = 0.0
        if self.time_end is None:
            self.time_end = 1.0
        if self.initial_value is None:
            if kwargs.get("initial") is "rand":
                self.initial_value = np.random.rand(self.dim_for_time_solver) * 1e-3
            else:
                self.initial_value = (np.sin(x[1])*np.sin(x[0])).reshape(self.dim_for_time_solver)

        if isinstance(self.epsilon, complex):
            self.numeric_type = np.complex
        self._u = np.zeros((self._m, self._m), dtype=np.complex128)
        # place to work on
        self._u_x = self._u.copy()
        self._u_y = self._u.copy()
        self._u_f = self._u.copy()
        self._u_angle = self._u.copy()
        self._u_edens = self._u.copy()
        self._B = self._u.copy()
        # arrays to work in fourier space
        self._k_od = np.hstack((np.arange(self._n+1, dtype=np.int64),
                               np.arange(self._n, dtype=np.int64)-self._n))
        self._k_y = self._k_od
        self._k_x = self._k_od.reshape(self._m, 1)
        for i in range(self._m-1):
            self._k_y = np.vstack((self._k_y, self._k_od))
            self._k_x = np.hstack((self._k_x, self._k_od.reshape(self._m, 1)))

        self._k_2 = self._k_x**2 + self._k_y**2
        self._k_4 = self._k_2**2


        if kwargs.get('delta_times_for_time_levels') is not None and self._mg_level is not None:
            assert_is_instance(kwargs['delta_times_for_time_levels'], (list, np.ndarray),
                               descriptor="Delta Times for Time Levels", checking_obj=self)
            for time_level in kwargs['delta_times_for_time_levels']:
                assert_is_instance(kwargs['delta_times_for_time_levels'][time_level], (list, np.ndarray),
                                   descriptor="Delta Times for Time Level %d" % time_level, checking_obj=self)
                for delta_time in kwargs['delta_times_for_time_levels'][time_level]:
                    self.initialize_direct_space_solver(time_level, delta_time, kwargs['mg_level'])
Beispiel #22
0
    def direct_implicit(self, *args, **kwargs):
        """Direct Implicit Formula for :math:`u'(t, \\phi_t) &= \\lambda u(t, \\phi_t)`
        """
        assert_named_argument('phis_of_time', kwargs, checking_obj=self)
        assert_named_argument('delta_node', kwargs, checking_obj=self)
        assert_named_argument('integral', kwargs, checking_obj=self)

        _phis = kwargs['phis_of_time']
        assert_is_instance(_phis, list, message="Direct implicit formula needs multiple phis.", checking_obj=self)
        assert_condition(len(_phis) == 3, ValueError, message="Need exactly three different phis.", checking_obj=self)
        for _phi in _phis:
            assert_condition(_phi.shape == self.dim_for_time_solver, ValueError,
                             message="Given phi is of wrong shape: %s != %s" % (_phi.shape, self.dim_for_time_solver),
                             checking_obj=self)

        # _phis[0] : previous iteration -> previous step
        # _phis[1] : previous iteration -> current step
        # _phis[2] : current iteration -> previous step

        _dn = kwargs['delta_node']
        # TODO: make this numerics check more advanced (better warning for critical numerics)
        if isinstance(self.lmbda, complex):
            assert_condition(_dn * self.lmbda.real != 1.0,
                             ArithmeticError, "Direct implicit formula for lambda={:f} and dn={:f} not valid. "
                             .format(self.lmbda, _dn) + "Try implicit solver.",
                             self)
        else:
            assert_condition(_dn * self.lmbda != 1.0,
                             ArithmeticError, "Direct implicit formula for lambda={:f} and dn={:f} not valid. "
                             .format(self.lmbda, _dn) + "Try implicit solver.",
                             self)

        _int = kwargs['integral']

        _fas = kwargs['fas'] \
            if 'fas' in kwargs and kwargs['fas'] is not None else 0.0

        if 'core' in kwargs \
                and (isinstance(kwargs['core'], (ImplicitSdcCore, ImplicitMlSdcCore))
                     or (isinstance(self.lmbda, complex) and isinstance(kwargs['core'], SemiImplicitMlSdcCore))):
            _new = (_phis[2] - _dn * self.lmbda * _phis[1] + _int + _fas) / (1 - self.lmbda * _dn)
            # LOG.debug("Implicit MLSDC Step:\n  %s = (%s - %s * %s * %s + %s + %s) / (1 - %s * %s)"
            #           % (_new, _phis[2], _dn, self.lmbda, _phis[1], _int, _fas, self.lmbda, _dn))
            return _new
        else:
            _new = \
                (_phis[2]
                 + _dn * (complex(0, self.lmbda.imag) * (_phis[2] - _phis[0]) - self.lmbda.real * _phis[1])
                 + _int + _fas) \
                / (1 - self.lmbda.real * _dn)
            # LOG.debug("Semi-Implicit MLSDC Step:\n  %s = (%s + %s * (%s * (%s - %s) - %s * %s) + %s + %s) / (1 - %s * %s)"
            #           % (_new, _phis[2],  _dn, complex(0, self.lmbda.imag), _phis[2], _phis[0], self.lmbda.real, _phis[1], _int, _fas, self.lmbda.real, _dn))
            return _new
Beispiel #23
0
 def __eq__(self, other):
     assert_is_instance(other, StepSolutionData,
                        message="Can not compare StepSolutionData with {}".format(class_name(other)),
                        checking_obj=self)
     return (
         self.time_point == other.time_point
         and self.dim == other.dim
         and self.numeric_type == other.numeric_type
         and np.array_equal(self.value, other.value)
         and self.error == other.error
         and self.residual == other.residual
     )
Beispiel #24
0
    def run(self, state, **kwargs):
        """Implicit Euler step method.

        .. math::

            u_{m+1}^{k+1} - \\Delta_\\tau F(t_{m+1}, u_{m+1}^{k+1}) =
                u_m^{k+1} + \\Delta_\\tau F(t_{m+1}, u_{m+1}^k) + \\Delta_t I_m^{m+1} \\left( F(\\vec{u}^k) \\right)

        Parameters
        ----------
        solver_state : :py:class:`.SdcSolverState`
        """
        super(ImplicitSdcCore, self).run(state, **kwargs)

        assert_is_instance(state, SdcSolverState, descriptor="State", checking_obj=self)
        assert_named_argument('problem', kwargs, types=IProblem, descriptor="Problem", checking_obj=self)
        _problem = kwargs['problem']

        _previous_iteration_current_step = self._previous_iteration_current_step(state)

        if problem_has_direct_implicit(_problem, self):
            _previous_iteration_previous_step = self._previous_iteration_previous_step(state)

            _sol = _problem.direct_implicit(phis_of_time=[_previous_iteration_previous_step.value,
                                                          _previous_iteration_current_step.value,
                                                          state.current_time_step.previous_step.value],
                                            delta_node=state.current_step.delta_tau,
                                            integral=state.current_step.integral,
                                            core=self)
        else:
            # using step-wise formula
            #   u_{m+1}^{k+1} - \Delta_\tau F(u_{m+1}^{k+1})
            #     = u_m^{k+1} - \Delta_\tau F(u_m^k) + \Delta_t I_m^{m+1}(F(u^k))
            # Note: \Delta_t is always 1.0 as it's part of the integral
            _expl_term = \
                (state.current_time_step.previous_step.value
                 - state.current_step.delta_tau
                 * _problem.evaluate_wrt_time(state.current_step.time_point,
                                              _previous_iteration_current_step.value)
                 + state.current_step.integral).reshape(-1)
            _func = lambda x_next: \
                _expl_term \
                + state.current_step.delta_tau \
                  * _problem.evaluate_wrt_time(state.current_step.time_point,
                                               x_next.reshape(_problem.dim_for_time_solver)).reshape(-1) \
                - x_next
            _sol = _problem.implicit_solve(state.current_step.value.reshape(-1), _func)

        if type(state.current_step.value) == type(_sol):
            state.current_step.value = _sol
        else:
            state.current_step.value = _sol[0]
Beispiel #25
0
    def _init_new_interval(self, start):
        """Initializes a new work interval

        Parameters
        ----------
        start : :py:class:`float`
            start point of new interval

        Returns
        -------
        has_work : :py:class:`bool`
            :py:class:`True` if new interval have been initialized;
            :py:class:`False` if no new interval have been initialized (i.e. new interval end would exceed end of time
            given by problem)
        """
        assert_is_instance(start, float, descriptor="Time Point", checking_obj=self)

        if start + self._dt > self.problem.time_end:
            return False

        if self.state and start == self.state.initial.time_point:
            return False

        self._init_new_state()

        # set width of current interval
        self.state.initial.solution.time_point = start
        self.state.initial.value = self.problem.initial_value.copy()
        self.state.delta_interval = self._dt

        self.__time_points = np.zeros(self.ml_provider.num_levels, dtype=np.object)
        self.__deltas = np.zeros(self.ml_provider.num_levels, dtype=np.object)

        # make sure the integrators are all set up correctly for the different levels
        for _level in range(0, self.ml_provider.num_levels):
            _integrator = self.ml_provider.integrator(_level)

            _integrator.transform_interval(self.state.interval)

            # print("nodes: %s" % _integrator.nodes)

            self.__time_points[_level] = np.zeros(_integrator.num_nodes, dtype=np.float)
            self.__deltas[_level] = np.zeros(_integrator.num_nodes, dtype=np.float)

            for _node in range(0, _integrator.num_nodes - 1):
                self.__time_points[_level] = deepcopy(_integrator.nodes)
                self.__deltas[_level][_node + 1] = _integrator.nodes[_node + 1] - _integrator.nodes[_node]

        # print("Time Points: %s" % self.__time_points)

        return True
    def __init__(self, fine_level, coarse_level, rst_stencil, ipl_stencil):
        assert_is_instance(fine_level, MultigridLevel1D, "Not an MultigridLevel1D")
        assert_is_instance(coarse_level, MultigridLevel1D, "Not an MultigridLevel1D")

        self.fl = fine_level
        self.cl = coarse_level

        assert_is_instance(ipl_stencil, InterpolationByStencilListIn1D)
        assert_is_instance(rst_stencil, RestrictionStencilPure)
        assert_condition(rst_stencil.ndim == 1,
                         ValueError, "Restriction Stencil"
                         + "has not the dimension 1")
        self.ipl = ipl_stencil
        self.rst = rst_stencil
        self.ipl_fine_views = []
        self.ipl_coarse_views = []
        # collect the views which are needed,
        if self.ipl.mode == "own":
            self.ipl_fine_views.append(self.fl.evaluable_view(
                self.ipl.stencil_list[0]))
            self.ipl_coarse_views(self.cl.mid)
        elif self.ipl.mode == "list":
            for stencil in self.ipl.stencil_list:
                self.ipl_fine_views.append(self.fl.evaluable_view(stencil))
                self.ipl_coarse_views.append(self.cl.mid)
        else:
            raise NotImplementedError("What do you have in mind?")

        self.rst_fine_view = self.fl.evaluable_view(self.rst)
        self.rst_coarse_view = self.cl.mid
Beispiel #27
0
    def run(self, state, **kwargs):
        """Explicit Euler step method.

        .. math::

            u_{m+1}^{k+1} = u_m^{k+1} + \\Delta_\\tau \\left( F(t_m, u_m^{k+1}) - F(t_m, u_m^k) \\right)
                                      + \\Delta_t I_m^{m+1} \\left( F(\\vec{u}^k) \\right)

        Parameters
        ----------
        solver_state : :py:class:`.MlSdcSolverState`
        """
        super(ExplicitMlSdcCore, self).run(state, **kwargs)

        assert_is_instance(state, MlSdcSolverState, descriptor="State", checking_obj=self)
        assert_named_argument('problem', kwargs, types=IProblem, descriptor="Problem", checking_obj=self)

        _problem = kwargs['problem']

        _previous_step = state.previous_step

        if not state.current_iteration.on_finest_level:
            LOG.debug("taking restringated or coarse-corrected value")
            if state.current_step != state.current_level.first:
                _previous_iteration_previous_step = state.current_iteration.current_level.previous_step.initial
            else:
                _previous_iteration_previous_step = state.current_iteration.current_level.initial
        else:
            _previous_iteration_previous_step = self._previous_iteration_previous_step(state)

        if not _previous_step.rhs_evaluated:
            _previous_step.rhs = _problem.evaluate_wrt_time(state.current_step.time_point, _previous_step.value)
        if not _previous_iteration_previous_step.rhs_evaluated:
            _previous_iteration_previous_step.rhs = \
                _problem.evaluate_wrt_time(state.current_step.time_point, _previous_iteration_previous_step.value)

        _fas = np.zeros(_previous_step.rhs.shape, dtype=_previous_step.rhs.dtype)
        if _previous_step.has_fas_correction():
            # LOG.debug("   previous step has FAS")
            _fas = _previous_step.fas_correction

        # Note: \Delta_t is always 1.0 as it's part of the integral
        # using step-wise formula
        # Formula:
        #   u_{m+1}^{k+1} = u_m^{k+1} + \Delta_\tau [ F(u_m^{k+1}) - F(u_m^k) ] + \Delta_t I_m^{m+1}(F(u^k))
        state.current_step.value = \
            (_previous_step.value
             + state.current_step.delta_tau * (_previous_step.rhs - _previous_iteration_previous_step.rhs)
             + state.current_step.integral + _fas)
Beispiel #28
0
    def __init__(self, value):
        """

        Parameters
        ----------
        value : :py:class:`numpy.ndarray`

        Raises
        ------
        ValueError:
            If ``value`` is not a :py:class:`numpy.ndarray`.
        """
        assert_is_instance(value, np.ndarray, descriptor="Diagnosis Values", checking_obj=self)
        self._data = value
        self._numeric_type = self.value.dtype
Beispiel #29
0
    def implicit_solve(self, next_x, func, method="hybr", **kwargs):
        """A solver for implicit equations.

        Finds the implicitly defined :math:`x_{i+1}` for the given right hand side function :math:`f(x_{i+1})`, such
        that :math:`x_{i+1}=f(x_{i+1})`.


        Parameters
        ----------
        next_x : :py:class:`numpy.ndarray`
            A starting guess for the implicitly defined value.
        rhs_call : :py:class:`callable`
            The right hand side function depending on the implicitly defined new value.
        method : :py:class:`str`
            *(optional, default=``hybr``)*
            Method fo the root finding algorithm. See `scipy.optimize.root
            <http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.root.html#scipy.optimize.root>` for
            details.

        Returns
        -------
        next_x : :py:class:`numpy.ndarray`
            The calculated new value.

        Raises
        ------
        ValueError :

            * if ``next_x`` is not a :py:class:`numpy.ndarray` of shape :py:attr:`.IProblem.dim`
            * if ``fun`` is not :py:class:`callable`
            * if computed solution is not a `:py:class:`numpy.ndarray`

        UserWarning :
            If the implicit solver did not converged, i.e. the solution object's ``success`` is not :py:class:`True`.
        """
        assert_is_instance(next_x, np.ndarray, descriptor="Initial Guess", checking_obj=self)
        assert_is_callable(func, descriptor="Function of RHS for Implicit Solver", checking_obj=self)
        sol = find_root(fun=func, x0=next_x.reshape(-1), method=method)
        if not sol.success:
            warnings.warn("Implicit solver did not converged.")
            LOG.debug("sol.x: %s" % sol.x)
            LOG.error("Implicit solver failed: %s" % sol.message)
        else:
            assert_is_instance(sol.x, np.ndarray, descriptor="Solution", checking_obj=self)
        return sol.x.reshape(self.dim_for_time_solver)
Beispiel #30
0
 def initialize_direct_space_solver(self, time_level, delta_time, mg_level=None):
     if mg_level is None:
         mg_level = self._mg_level
     assert_is_instance(mg_level, IMultigridLevel, descriptor="Multigrid Level", checking_obj=self)
     _stencil = Stencil(self.mg_stencil(delta_time, mg_level.h))
     # LOG.debug("Stencil for dt=%f, h=%f: %s" % (delta_time, mg_level.h, _stencil.arr))
     time_level = str(time_level)
     delta_time = str(delta_time)
     if self._direct_solvers.get(time_level) is None:
         # LOG.debug("Initializing Solvers for Time Level '%s'" % time_level)
         self._direct_solvers[time_level] = {}
     # LOG.debug("  Initializing Solver for Time Level '%s' and Delta Node '%s'" % (time_level, delta_time))
     # LOG.debug("    shape: %s" % (mg_level.mid.shape))
     self._direct_solvers[time_level][delta_time] = {
         'mg_level': mg_level,
         'stencil': _stencil,
         'solver': _stencil.generate_direct_solver(mg_level.mid.shape)
     }