Source code for odespy.rkf45

"""Module for wrapping rkf45.py."""

from solvers import Solver, Adaptive
import numpy as np


[docs]class RKF45(Adaptive): """ Wrapper for rkf45.f, a FORTRAN solver designed to solve non-stiff and mildly stiff differential equations by the well-known Runge-Kutta-Fehlberg (4,5) method. The FORTRAN source rkf45.f can be obtained from Netlib. """ quick_description = "Adaptive Runge-Kutta-Fehlberg (4,5) method (rkf45.f)" _optional_parameters = Adaptive._optional_parameters + ['f_f77'] # The following step parameters are illegal for rkf45.f # and therefore removed (class Adaptive adds them in the above statement) _optional_parameters.remove('first_step') _optional_parameters.remove('min_step') _optional_parameters.remove('max_step') _iflag_messages = { 2: 'integration reached tout. indicates successful retur ' 'and is the normal mode for continuing integration.', -2: 'a single successful step in the direction of tout ' 'has been taken. normal mode for continuing ' 'integration one step at a time.', 3: 'integration was not completed because relative error ' 'tolerance was too small. relerr has been increased ' 'appropriately for continuing.', 4: 'integration was not completed because more than ' '3000 derivative evaluations were needed. this ' 'is approximately 500 steps.', 5: 'integration was not completed because solution ' 'vanished making a pure relative error test' 'impossible. must use non-zero abserr to continue. ' 'using the one-step integration mode for one step ' 'is a good way to proceed.', 6: 'integration was not completed because requested ' 'accuracy could not be achieved using smallest ' 'allowable stepsize. user must increase the error ' 'tolerance before continued integration can be ' 'attempted.', 7: 'it is likely that rkf45 is inefficient for solving ' 'this problem. too much output is restricting the ' 'natural stepsize choice. use the one-step integrator ' 'mode.', 8: 'invalid input parameters ' 'this indicator occurs if any of the following is ' 'satisfied - t=tout and iflag .ne. +1 or -1 ' 'relerr or abserr .lt. 0. iflag .eq. 0 or .lt. -2 or .gt. 8', }
[docs] def initialize(self): '''Import extension module _rkf45 and check that it exists.''' try: import _rkf45 self._rkf45 = _rkf45 except ImportError: raise ImportError('Cannot find the extension module _rkf45.\nRun setup.py again and investigate why _rkf45.so was not successfully built.')
[docs] def adjust_parameters(self): self._parameters['rtol']['type'] = float self._parameters['rtol']['extra_check'] = lambda x: x >= 0.0 self._parameters['atol']['type'] = float self._parameters['atol']['extra_check'] = lambda x: x >= 0.0
[docs] def initialize_for_solve(self): if hasattr(self, 'f'): # If f is input in form of f(u,t), wrap f to f_f77 for Fortran code. f = self.f self.f_f77 = lambda t,u: np.asarray(f(u,t)) elif hasattr(self, 'f_f77'): # If f is input in form of f(t,u) (usually in Fortran), # wrap f_f77 to the general form f(u,t) for switch_to() f_f77 = self.f_f77 self.f = lambda u,t: np.asarray(f_f77(t,u)) Solver.initialize_for_solve(self)
[docs] def advance(self): u, t, n, rtol, atol = self.u, self.t, self.n, self.rtol, self.atol advance = self._rkf45.advance f = getattr(self.f_f77, '_cpointer', self.f_f77) unew, iflag = advance(f, u[n], t[n], t[n+1], rtol, atol) if iflag > 2: raise Exception('rkf45.f: iflag=%d > 2 (abort)' % iflag) self.iflag = 'iflag=%d\n%s' % (iflag, RKF45._iflag_messages[iflag]) return unew