def test_odeoptions_alloptions(self): def mass(t, y, c): return [[t, y[0]], [c, t + 1]] def events(t, y, c): return [[1, 1], [1, 1], [1, 1]] y = [1, 2] t = 0 extra = [1] try: options = { 'RelTol': 1e-2, 'AbsTol': [1e-4, 1e-5], 'NormControl': 'on', 'NonNegative': [1], 'Refine': 3, 'Stats': 'off', 'InitialStep': 2.3, 'MaxStep': 4.2e1, 'Events': events, 'Mass': mass, 'MStateDependence': 'weak' } odeoptions(options, t, y, extra) except: self.fail("All option correct test failed")
def test_odeoptions_abstol(self): y = [1, 2] t = 0 extra = [] try: options = {'AbsTol': 1e-2} odeoptions(options, t, y, extra) options = {'AbsTol': 100} odeoptions(options, t, y, extra) options = {'AbsTol': 0} odeoptions(options, t, y, extra) options = {'AbsTol': [0, 1]} odeoptions(options, t, y, extra) options = {'AbsTol': [0, 1.0]} odeoptions(options, t, y, extra) except: self.fail("AbsTol option correct test failed") options = {'AbsTol': -1e-2} self.assertRaises(ValueError, odeoptions, options, t, y, extra) options = {'AbsTol': '1'} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'AbsTol': [1, 1.2, 3]} self.assertRaises(IndexError, odeoptions, options, t, y, extra) options = {'AbsTol': [-1, 1.2]} self.assertRaises(ValueError, odeoptions, options, t, y, extra) options = {'AbsTol': ['1', 1.2]} self.assertRaises(TypeError, odeoptions, options, t, y, extra)
def test_odeoptions_nooptions(self): options = {} y = [1, 2] t = 1 try: odeoptions(options, t, y, []) except: self.fail("No option correct test failed")
def test_odeoptions_stats(self): y = [1, 2] t = 0 extra = [] try: options = {'Stats': 'on'} odeoptions(options, t, y, extra) options = {'Stats': 'off'} odeoptions(options, t, y, extra) except: self.fail("Stats option correct test failed") options = {'Stats': 2} self.assertRaises(ValueError, odeoptions, options, t, y, extra) options = {'Stats': 'none'} self.assertRaises(ValueError, odeoptions, options, t, y, extra)
def test_odeoptions_normcontrol(self): y = [1, 2] t = 0 extra = [] try: options = {'NormControl': 'on'} odeoptions(options, t, y, extra) options = {'NormControl': 'off'} odeoptions(options, t, y, extra) except: self.fail("NormControl option correct test failed") options = {'NormControl': 2} self.assertRaises(ValueError, odeoptions, options, t, y, extra) options = {'NormControl': 'none'} self.assertRaises(ValueError, odeoptions, options, t, y, extra)
def test_odeoptions_mstatedependence(self): y = [1, 2] t = 0 extra = [] try: options = {'MStateDependence': 'weak'} odeoptions(options, t, y, extra) options = {'MStateDependence': 'none'} odeoptions(options, t, y, extra) except: self.fail("Mass option correct test failed") options = {'MStateDependence': 'strong'} self.assertRaises(ValueError, odeoptions, options, t, y, extra) options = {'MStateDependence': 1.0} self.assertRaises(ValueError, odeoptions, options, t, y, extra) options = {'MStateDependence': ['weak']} self.assertRaises(ValueError, odeoptions, options, t, y, extra)
def test_odeoptions_refine(self): y = [1, 2] t = 0 extra = [] try: options = {'Refine': 1} odeoptions(options, t, y, extra) options = {'Refine': 5} odeoptions(options, t, y, extra) except: self.fail("Refine option correct test failed") options = {'Refine': 1e-2} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'Refine': -2} self.assertRaises(ValueError, odeoptions, options, t, y, extra) options = {'Refine': 0} self.assertRaises(ValueError, odeoptions, options, t, y, extra)
def test_odeoptions_maxstep(self): y = [1, 2] t = 0 extra = [] try: options = {'MaxStep': 1} odeoptions(options, t, y, extra) options = {'MaxStep': 5e-2} odeoptions(options, t, y, extra) except: self.fail("MaxStep option correct test failed") options = {'MaxStep': -1e-2} self.assertRaises(ValueError, odeoptions, options, t, y, extra) options = {'MaxStep': -1} self.assertRaises(ValueError, odeoptions, options, t, y, extra) options = {'MaxStep': [1.0]} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'MaxStep': 'on'} self.assertRaises(TypeError, odeoptions, options, t, y, extra)
def test_odeoptions_reltol(self): y = [1, 2] t = 0 extra = [] try: options = {'RelTol': 1e-2} odeoptions(options, t, y, extra) options = {'RelTol': 100} odeoptions(options, t, y, extra) options = {'RelTol': 1e-12} odeoptions(options, t, y, extra) except: self.fail("RelTol option correct test failed") options = {'RelTol': -1e-2} self.assertRaises(ValueError, odeoptions, options, t, y, extra) options = {'RelTol': '1'} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'RelTol': [1, 1.2]} self.assertRaises(TypeError, odeoptions, options, t, y, extra)
def test_odeoptions_nonnegative(self): y = [1, 2] t = 0 extra = [] try: options = {'NonNegative': []} odeoptions(options, t, y, extra) options = {'NonNegative': [1]} odeoptions(options, t, y, extra) options = {'NonNegative': [0, 1]} odeoptions(options, t, y, extra) except: self.fail("NonNegative option correct test failed") options = {'NonNegative': [2]} self.assertRaises(IndexError, odeoptions, options, t, y, extra) options = {'NonNegative': [0, '2']} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'NonNegative': [1.0]} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'NonNegative': 'one'} self.assertRaises(TypeError, odeoptions, options, t, y, extra)
def test_odeoptions_mass(self): y = [1, 2] t = 0 extra = [] try: options = {'Mass': [[1, 1], [0, 2]]} odeoptions(options, t, y, extra) options = {'Mass': np.array([[1, 1], [0, 2]])} odeoptions(options, t, y, extra) def mass(t): return [[t, 0], [0, t + 1]] options = {'Mass': mass} odeoptions(options, t, y, extra) def mass(t, c): return [[t, 0], [c, t + 1]] options = {'Mass': mass} odeoptions(options, t, y, [0]) def mass(t): return np.array([[t, 0], [0, t + 1]]) options = {'Mass': mass} odeoptions(options, t, y, extra) def mass(t, c): return np.array([[t, 0], [c, t + 1]]) options = {'Mass': mass} odeoptions(options, t, y, [0]) def mass(t, y): return [[t, y[0]], [0, t + 1]] options = {'Mass': mass} odeoptions(options, t, y, extra) def mass(t, y, c): return [[t, y[0]], [c, t + 1]] options = {'Mass': mass} odeoptions(options, t, y, [1]) def mass(t, y): return np.array([[t, y[0]], [0, t + 1]]) options = {'Mass': mass} odeoptions(options, t, y, extra) def mass(t, y, c): return np.array([[t, y[0]], [c, t + 1]]) options = {'Mass': mass} odeoptions(options, t, y, [1]) except: self.fail("Mass option correct test failed") options = {'Mass': 'on'} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'Mass': [1, 2, 4]} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'Mass': [1.2, 3]} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'Mass': [1, 'one']} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'Mass': [[1, 2], 1]} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'Mass': [[1, 2], [1, 2, 2]]} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'Mass': [[1, 2], [1, 'on']]} self.assertRaises(ValueError, odeoptions, options, t, y, extra) def mass(t, c): return [[1, 2], [1, 2]] options = {'Mass': mass} self.assertRaises(Exception, odeoptions, options, t, y, [1, 2]) def mass(t, y, c): return [[1, 2], [1, 2]] options = {'Mass': mass} self.assertRaises(Exception, odeoptions, options, t, y, extra) def mass(t): return 'on' options = {'Mass': mass} self.assertRaises(TypeError, odeoptions, options, t, y, extra) def mass(t): return [1, 2, 4] options = {'Mass': mass} self.assertRaises(TypeError, odeoptions, options, t, y, extra) def mass(t): return [1.2, 3] options = {'Mass': mass} self.assertRaises(TypeError, odeoptions, options, t, y, extra) def mass(t): return [[1, 2], 1] options = {'Mass': mass} self.assertRaises(TypeError, odeoptions, options, t, y, extra) def mass(t): return [[1, 2], [1, 2, 2]] options = {'Mass': mass} self.assertRaises(TypeError, odeoptions, options, t, y, extra) def mass(t): return [[1, 2], [1, 'on']] options = {'Mass': mass} self.assertRaises(ValueError, odeoptions, options, t, y, extra) def mass(t, y): return 'on' options = {'Mass': mass} self.assertRaises(TypeError, odeoptions, options, t, y, extra) def mass(t, y): return [1, 2, 4] options = {'Mass': mass} self.assertRaises(TypeError, odeoptions, options, t, y, extra) def mass(t, y): return [1.2, 3] options = {'Mass': mass} self.assertRaises(TypeError, odeoptions, options, t, y, extra) def mass(t, y): return [[1, 2], 1] options = {'Mass': mass} self.assertRaises(TypeError, odeoptions, options, t, y, extra) def mass(t, y): return [[1, 2], [1, 2, 2]] options = {'Mass': mass} self.assertRaises(TypeError, odeoptions, options, t, y, extra) def mass(t, y): return [[1, 2], [1, 'on']] options = {'Mass': mass} self.assertRaises(ValueError, odeoptions, options, t, y, extra)
def test_odeoptions_events(self): y = [1, 2] t = 0 try: extra = [] def events(t, y): return [3.2], [1], [-1] options = {'Events': events} odeoptions(options, t, y, extra) extra = [1, [3, 2]] def events(t, y, c, b): return [3.2, 2.1], [1, 0], [-1, 1] options = {'Events': events} odeoptions(options, t, y, extra) y = [1, 2] extra = [[3, 2]] def events(t, y, c): return [3.2, c[0]], [1, 0], [-1, 1] options = {'Events': events} odeoptions(options, t, y, extra) except: self.fail("Events option correct test failed") extra = [] options = {'Events': [[3.2, 2.1], [1, 0], [-1, 1]]} self.assertRaises(TypeError, odeoptions, options, t, y, extra) options = {'Events': 'on'} self.assertRaises(TypeError, odeoptions, options, t, y, extra) def events(t, y): return [3.2, 2.1, 3], [1, 0], [-1, 1] options = {'Events': events} self.assertRaises(ValueError, odeoptions, options, t, y, extra) def events(t, y): return [3.2, 2.1], [1, 0, 1], [-1, 1] options = {'Events': events} self.assertRaises(ValueError, odeoptions, options, t, y, extra) def events(t, y): return [3.2, 2.1], [1, 0], [-1, 1, 0] options = {'Events': events} self.assertRaises(ValueError, odeoptions, options, t, y, extra) def events(t, y): return [3.2, '2.1'], [1, 0], [-1, 1] options = {'Events': events} self.assertRaises(ValueError, odeoptions, options, t, y, extra) def events(t, y): return [3.2, '2.1'], [1, 0], [-1, 1] options = {'Events': events} self.assertRaises(ValueError, odeoptions, options, t, y, extra) def events(t, y): return [[3.2, 2.1], [-1, 0], [0, 1]] options = {'Events': events} self.assertRaises(ValueError, odeoptions, options, t, y, extra) def events(t, y): return [[3.2, 2.1], [1, 0], [0, 2]] options = {'Events': events} self.assertRaises(ValueError, odeoptions, options, t, y, extra)
def odearguments(ode, tspan, y0, options, extras): '''Function to verify the inputs of ode45 meet the specifications. Parameters ---------- ode : callable ode function which will be evaluated. tspan : array_like, shape(2,) || shape(k,) Span over which the function should be evaluated, can be either be a pair [t_0,t_end] or an array of specific points. y0 : array_like, shape(n,) Initial values. options : dictionary Options, see ode45 sepifications for more information. extras : array_like, shape(k,) Extra arguments in the function evaluation, if no extra arguments are used then extra is empty. Returns ------- neq : integer Number of equations. tspan : array_like, shape(2,) || shape(k,) Span over which the function should be evaluated, can be either be a pair [t_0,t_end] or an array of specific points. ntspan : integer Size of tspan. nex : 2 Used in main ode45 t0 : scalar First time to be evaluated. tfinal : scalar Final time to be evaluated. tdir : scalar Whether tfinal is greater than t0, 1 if tfinal is greater and -1 otherwise. y0 : array_like, shape(n,) Initial values. f0 : array_like, shape(n,) Evaluation of ode for intial values y0. args : array_like, shape(k,) Extra arguments. odeFcn : callable ode function. options : dictionary. options dictionary. threshold : scalar || array_like, shape(n,) Difference between the absolute tolerance and relative tolerance, if the AbsTol option is a scalar then threshold is a scalar, and a array if AbsTol is an array. rtol : scalar Relative tolerance (RelTol option). normcontrol : Bool True if NormControl option is 'on', False otherwise. normy : scalar Norm of the intial values. hmax : scalar Maximum step size. htry : scalar Initial step size. htspan : scalar Difference between t_0 and t_end. dataType : numpy dtype float64. ''' #Verify y0 if not isinstance(y0, np.ndarray) and not isinstance(y0, list): raise TypeError('odearguments: y0: must be a list or ndarray') else: if len(y0) == 0: raise ValueError( 'odearguments: y0: must have at least one initial value') for i in y0: if not isinstance(i, num.Number): raise TypeError('odearguments: y0: elements must be numbers') neq = len(y0) #Verify tspan if not isinstance(tspan, np.ndarray) and not isinstance(tspan, list): raise TypeError('odearguments: tspan: must be a list or ndarray') else: if len(tspan) < 2: raise ValueError( 'odearguments: tspan: must have at least two initial values') for i in tspan: if not isinstance(i, num.Number): raise TypeError( 'odearguments: tspan: elements must be numbers') #Verify ode if not callable(ode): raise TypeError('odearguments: ode: ode function is not callable') else: sig = signature(ode) if len(sig.parameters) != 2 + len(extras): raise TypeError( 'odearguments: ode: ode function must have the correct number of arguments' ) else: result = feval(ode, tspan[0], y0, extras) if not isinstance(result, np.ndarray) and not isinstance( result, list): raise TypeError( 'odearguments: ode: ode function must return a list or ndarray type' ) else: if len(result) != len(y0): raise ValueError( 'odearguments: ode: ode function must return a list or ndarray type of length equal to y0' ) for i in result: if not isinstance(i, num.Number): raise TypeError( 'odearguments: ode: elements must be numbers') #Check options odeoptions(options, tspan[0], y0, extras) htspan = abs(tspan[1] - tspan[0]) ntspan = len(tspan) t0 = tspan[0] nex = 2 tfinal = tspan[-1] args = extras #Verify tspan if t0 == tfinal: raise ValueError( 'odearguments: tspan: first value and final value must be different' ) tdir = np.sign(tfinal - t0) if any(tdir * np.diff(tspan) <= 0): raise ValueError('odearguments: tspan: must be monotonic') f0 = feval(ode, t0, y0, extras) dataType = 'float64' #Relative tolerance rtol = odeget(options, 'RelTol', 1e-3) if rtol < 100 * np.finfo(dataType).eps: rtol = 100 * np.finfo(dataType).eps warnings.warn('odearguments: rtol: rtol was too small') #Absolute tolerance atol = odeget(options, 'AbsTol', 1e-6) normcontrol = (odeget(options, 'NormControl', 'off') == 'on') if normcontrol: normy = np.linalg.norm(y0) else: normy = 0 if isinstance(atol, list): if normcontrol: raise ValueError( 'odearguments: NormControl: when \'on\' AbsTol must be a scalar' ) threshold = [tol / rtol for tol in atol] else: threshold = atol / rtol #Default max step is 1/10 size of the interval hmax = min(abs(tfinal - t0), abs(odeget(options, 'MaxStep', 0.1 * (tfinal - t0)))) htry = odeget(options, 'InitialStep', 0) odeFcn = ode return neq, tspan, ntspan, nex, t0, tfinal, tdir, y0, f0, args, odeFcn, options, threshold, rtol, normcontrol, normy, hmax, htry, htspan, dataType