コード例 #1
0
ファイル: odemass.py プロジェクト: armoreau/master-thesis
def odemass(FcnHandlesUsed,ode,t0,y0,options,extras):
    
    massType = 0 
    massFcn = None
    massArgs = None
    massM = np.eye(len(y0))  
    dMoptions = None    # options for odenumjac computing d(M(t,y)*v)/dy
     
    Moption = options.Mass
    if Moption is None :
        return massType, massM, massFcn
    elif not callable(Moption):
        massType = 1
        massM = Moption
        return massType, massM, massFcn
    else : #Moption is a matrix function
        massFcn = Moption
        massArgs = extras
        Mstdep = options.MStateDependence
        if Mstdep == 'none': # time-dependent only
            massType = 2
            massM = feval(massFcn,t0,None,massArgs)
        elif Mstdep == 'weak': # state-dependent
            massType = 3
            massM = feval(massFcn,t0,y0,massArgs)
        else:
            raise Exception("python:odemass:MStateDependenceMassType")
            
        return massType, massM, massFcn
コード例 #2
0
def Newtons(fun, fun_pr, a, b, tol, maxIter):
    x = []
    y = []
    y_pr = []
    x.append(((a + b) / 2.0))
    y.append(feval(fun, [x[0]]))
    y_pr.append(feval(fun_pr, [x[0]]))
    for i in range(1, maxIter):
        x.append(x[i - 1] - y[i - 1] / y_pr[i - 1])
        y.append(feval(fun, [x[i]]))
        if abs(x[i] - x[i - 1]) < tol:
            print 'Newton method has converged'
            break
        y_pr.append(feval(fun_pr, [x[i]]))
        iteration = i
    if (iteration >= maxIter):
        print 'zero not found to desired tolerance'
    n = len(x)
    k = np.linspace(1, n, n)
    out = np.zeros((n, 3))
    for i in range(n):
        out[i, 0] = k[i]
        out[i, 1] = x[i]
        out[i, 2] = y[i]
    np.set_printoptions(precision=16)
    #    print '  step        a         b          x          y'
    #    print out
    return [n, out[n - 1, 1], out[n - 1, 2]]
コード例 #3
0
    def test_feval_basic(self):
        def f1(t, y):
            return t * y[0]

        def f2(t):
            return 3 * t

        def f3(t, y, c):
            return t * c * y[1]

        def f4(t, c):
            return t * c[0]

        try:
            self.assertEqual(feval(f1, 1.5, [2, 3], []), 3)
            self.assertEqual(feval(f1, 1.5, [3], []), 4.5)
            self.assertEqual(feval(f2, 1.5, None, []), 4.5)
            self.assertEqual(feval(f2, 2, None, []), 6)
            self.assertEqual(feval(f3, 2, [0, 2], [3]), 12)
            self.assertEqual(feval(f3, 7, [0, 1], [4]), 28)
            self.assertEqual(feval(f4, 2, None, [[4]]), 8)
            self.assertEqual(feval(f4, 5, None, [[2]]), 10)

            self.assertRaises(Exception, feval, f1, 1.5, None, [])
            self.assertRaises(Exception, feval, f1, 1.5, [1, 2], [3])
            self.assertRaises(Exception, feval, f2, 1.5, [1, 4], [])
            self.assertRaises(Exception, feval, f2, 1.5, None, [3])
            self.assertRaises(Exception, feval, f3, 1.5, None, [])
            self.assertRaises(Exception, feval, f3, 1.5, [1, 2], [])
            self.assertRaises(Exception, feval, f4, 1.5, None, [])
            self.assertRaises(Exception, feval, f4, 1.5, [1, 2], [3])
        except:
            self.fail("feval correct test failed")
コード例 #4
0
def odeevents(t0,y0,options,extras):
    
    '''Event helper function for ode45.
        
    Parameters
    ----------
    t0 : scalar
        Initial time to be evaluated.
    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
    -------
    haveeventfun : bool
        True if event function contained in options, False otherwise.
    eventFcn : callable || None
        Event function if contained in the options, None otherwise.
    eventArgs : array_like, shape(k,) || None
        extras if event function contained in options, None otherwise.
    eventValue : array_like, shape(n,) || None
        Values of the event function for the initial values if event function contained in options,
        None otherwise.
    teout : ndarray, shape(0,)
        Empty numpy array to store events t values.
    yeout : ndarray, shape(0,)
        Empty numpy array to store events y values.
    ieout : ndarray, shape(0,)
        Empty numpy array to store events index values.
    '''
    
    haveeventfun = False
    eventArgs = None
    eventValue = None
    
    teout = np.array([])
    yeout = np.array([])
    ieout = np.array([])
    
    eventFcn=odeget(options,'Events',None)
    
    if eventFcn==None:
        #No event option
        return haveeventfun,eventFcn,eventArgs,eventValue,teout,yeout,ieout
    
    haveeventfun = True
    eventArgs = extras
    eventValue,_,_ = feval(eventFcn,t0,y0,eventArgs)
    
    return haveeventfun,eventFcn,eventArgs,eventValue,teout,yeout,ieout
    def test_odemassexplicit_mass3(self):
        odeFcn, odeArgs = odemassexplicit(3, self.f, self.extra, self.mass3,
                                          [])
        y = feval(odeFcn, self.t, self.y, odeArgs)
        result = np.array([1, 2, 3])

        self.assertEqual(odeFcn, explicitSolverHandleMass3)
        self.assertEqual(len(odeArgs), 3)
        self.assertEqual(odeArgs[0], self.f)
        self.assertEqual(odeArgs[1], self.mass3)
        for i in range(len(result)):
            self.assertAlmostEqual(y[i], result[i])
        self.assertEqual(odeArgs[2], [1])
    def test_odemassexplicit_mass1sparse(self):
        odeFcn, odeArgs = odemassexplicit(1, self.f, self.extra, [],
                                          sp.csr_matrix(self.mass1))
        superLU = spl.splu(sp.csr_matrix(self.mass1))
        y = feval(odeFcn, self.t, self.y, odeArgs)
        result = np.array([1, 2, 3])

        self.assertEqual(odeFcn, explicitSolverHandleMass1sparse)
        self.assertEqual(len(odeArgs), 3)
        self.assertEqual(odeArgs[0], self.f)
        self.assertEqual((superLU.L - odeArgs[1].L).nnz, 0)
        self.assertEqual((superLU.U - odeArgs[1].U).nnz, 0)
        for i in range(len(result)):
            self.assertAlmostEqual(y[i], result[i])
        self.assertEqual(odeArgs[2], [1])
    def test_odemassexplicit_mass1(self):
        odeFcn, odeArgs = odemassexplicit(1, self.f, self.extra, [],
                                          self.mass1)
        PL, U = lg.lu(self.mass1, permute_l=True)
        y = feval(odeFcn, self.t, self.y, odeArgs)
        result = np.array([1, 2, 3])

        self.assertEqual(odeFcn, explicitSolverHandleMass1)
        self.assertEqual(len(odeArgs), 4)
        self.assertEqual(odeArgs[0], self.f)
        for i in range(len(PL)):
            self.assertAlmostEqual(y[i], result[i])
            for j in range(len(PL[0])):
                self.assertEqual(odeArgs[1][i, j], PL[i, j])
                self.assertEqual(odeArgs[2][i, j], U[i, j])
        self.assertEqual(odeArgs[3], [1])
コード例 #8
0
def odeevents(FcnHandlesUsed,ode,t0,y0,options,extras):
    
    haveeventfun = 0   # no Events function
    eventArgs = None
    eventValue = None
    teout = np.array([])
    yeout = np.array([])
    ieout = np.array([])
    
    eventFcn = options.Events
    if eventFcn is None :
      return haveeventfun, eventFcn, eventArgs, eventValue, teout, yeout, ieout
    
    if FcnHandlesUsed :    # function handles used 
      haveeventfun = 1   # there is an Events function
      eventArgs = extras
      [eventValue, trash1, trash2] = feval(eventFcn,t0,y0,eventArgs)
    
    return haveeventfun, eventFcn, eventArgs ,eventValue, teout, yeout, ieout
コード例 #9
0
def explicitSolverHandleMass1(t, y, odeFcn, PL, U, varargin):
    #Wrapper function for dense mass matrix
    ode = feval(odeFcn, t, y, varargin)
    xp = lg.lstsq(PL, ode)[0]
    yp = lg.lstsq(U, xp)[0]
    return yp
コード例 #10
0
def explicitSolverHandleMass3(t, y, odeFcn, massFcn, varargin):
    #Wrapper function for state-time dependent function
    mass = feval(massFcn, t, y, varargin)
    ode = feval(odeFcn, t, y, varargin)
    yp = lg.lstsq(mass, ode)[0]
    return yp
コード例 #11
0
def local_odeFcn_nonnegative(t, y, ode, idxNonNegative, varargin=None):
    yp = feval(ode, t, y, varargin)
    ndx = [i for i in range(len(idxNonNegative)) if y[i] <= 0]
    for i in ndx:
        yp[i] = np.maximum(yp[i], 0)
    return yp
コード例 #12
0
def explicitSolverHandleMass1sparse(t, y, odeFcn, superLU, varargin):
    #Wrapper function for sparse mass matrix
    ode = feval(odeFcn, t, y, varargin)
    yp = superLU.solve(np.array(ode))
    return yp
def ode45(odefun, tspan, y0, options=None, varargin=None):
    '''Function to solve non-stiff differential equations using the dormund prince method
        with adaptive step. The system of differential equations takes the form y' = f(t,y)
        with y(0) = y_0 for t = {t_0, t_end}.
            
    Parameters
    ----------
    odefun : callable
        Callable function which represents the system of differential equations to be
        solved. The function must take the form y' = f(t,y), eg:
            
            def dydt(t,y):
                return [math.cos(t), y[1] * math.sin(t)]
                
        Where t must be a float and y must be an array_like of size n, where n is the
        size of the system. The function must return an array_like with the same size
        of size n.
            
    tspan : array_like, shape(2,) || shape(k,)
        This array represents the span over which odefun will be evaluated. It can either
        be an array of size 2 which represents [t_0, t_end], or it can either be a larger
        array which would represent a series of chosen points. If tspan is a series of 
        chosen points, then the function will only be evaluated at those points.
    
    y0 : array_like, shape(n,)
        This array are the initial values for the odefun function. It must be the same size
        as the array returned by the odefun.
    
    options : dictionary
        This dictionary contains the user options, the keys are represented by the option
        name, and the values are the value of the options. If a default value is shown, then
        this is the value the option will be set to automatically. The possible options are:
            
            AbsTol : float || array_like, shape(n,)    (default : 1e-6)
                Absolute error tolerance, can be a positive float or an array of positive
                floats.
                
            RelTol : float    (default : 1e-3)
                Relative error tolerance.
                
            NormControl : 'on' || 'off'    (default : 'off')
                If 'off' then error at each step:
                    error[i] <= max(RelTol * y[i], AbsTol[i])
                If 'on' then error at each step:
                    |error| <= max(RelTol * |y|, |AbsTol|)
                If NormControl is 'on' then AbsTol must be a float and not an array_like.
            
            Stats : 'on' || 'off'    (default : 'off')
                If 'on' then the function will print a series of stats about the execution.
            
            InitialStep : float
                Size of the initial step, must be a positive float.
                
            MaxStep : float    (default : 0.1 * abs(t_0 - t_end))
                Size of the maximun step, must be a positive float.
            
            Refine : integer    (default : 4)
                Determines the refinement to be performed at each step. If refine is set to 
                one, then no refinement will be performed.
                
            NonNegative : array_like    (default : [])
                List solutions of the differential system which will be kept positive. The
                list must contain only integers representing the indices of the solutions.
            
            Events : callable
                Function which must return value, isterminal, direction, all of which are 
                array_like of the same size. When the value of any of the values is 0 then
                an event is triggered. The isterminal determines whether the event should stop
                the execution and can only take value of 0 or 1. The direction determines from
                which direction the event should be triggered, if -1 then the event triggers
                if coming from the negative direction, whereas 1 will trigger if coming from 
                the positive direction, and 0 will trigger when coming from any direction. E.g :
                    
                    def events(t,y):
                        value = [10 - t, y[1]]
                        isterminal = [0, 1]
                        direction = [1, 0]
                        return value, isterminal, direction
                
            Mass : callable || array_like, shape(n,n)
                The mass option can either be a constant mass matrix, a time dependent function
                or a state-time dependent function.
                
                    Mass Matrix : array_like, shape(n,n)
                        Will solve for y s.t. M y' = f(t,y), M must be a square matrix.
                    
                    Time Dependent Function : callable
                        Will solve for y s.t. M(t) y' = f(t,y), M(t) must be a function in the
                        which takes t as argument an return an array_like(n,n)
                    
                    State-Time Dependent Function : callable
                        Will solve for y s.t. M(t,y) y' = f(t,y), M(t,y) must be a function in the
                        which takes t and y as argument an return an array_like(n,n)
            
            MStateDependence : 'none' || 'weak'    (default : 'none')
                Must be set to 'weak' if the Mass option is a state-time dependent function, otherwise
                it must be set to 'none'.
                    
    varargin : array_like, shape(t,)
        These are extra arguments that can be passed to the odefun. For example:
            
            def dydt(t,y,a,b):
                return [math.cos(t) + a, y[1] * math.sin(t) + b]
            
            varagin = [a,b]
        Note that these extra argument will also be passed to any events or mass function.
            

    Returns
    -------
    _ : odefinalize
        The function will return an object of type odefinalize (see odefinalize).
    
    '''

    solver_name = 'ode45'

    nsteps = 0
    nfailed = 0
    nfevals = 0

    if isinstance(options, type(None)):
        options = {}

    if isinstance(varargin, type(None)):
        varargin = []

    #Handle solver arguments
    neq, tspan, ntspan, nex, t0, tfinal, tdir, y0, f0, odeArgs, odeFcn, options, threshold, rtol, normcontrol, normy, hmax, htry, htspan, dataType = odearguments(
        odefun, tspan, y0, options, varargin)
    nfevals = nfevals + 1

    refine = max(1, odeget(options, 'Refine', 4))
    if len(tspan) > 2:
        outputAt = 'RequestedPoints'
    elif refine == 1:
        outputAt = 'SolverSteps'
    else:
        outputAt = 'RefinedSteps'
        s = np.array(range(1, refine)) / refine

    printstats = (odeget(options, 'Stats', 'off') == 'on')

    #Handle the event function
    haveEventFcn, eventFcn, eventArgs, valt, teout, yeout, ieout = odeevents(
        t0, y0, options, varargin)

    #Handle the mass matrix
    Mtype, M, Mfun = odemass(t0, y0, options, varargin)
    if Mtype > 0:
        odeFcn, odeArgs = odemassexplicit(Mtype, odeFcn, odeArgs, Mfun, M)
        f0 = feval(odeFcn, t0, y0, odeArgs)
        nfevals = nfevals + 1

    #Non-negative solution components
    idxNonNegative = odeget(options, 'NonNegative', [])
    nonNegative = False
    if len(idxNonNegative) != 0:
        odeFcn, thresholdNonNegative = odenonnegative(odeFcn, y0, threshold,
                                                      idxNonNegative)
        f0 = feval(odeFcn, t0, y0, odeArgs)
        nfevals = nfevals + 1
        nonNegative = True

    t = t0
    y = y0

    #Memory Allocation
    nout = 1
    yout = np.array([], dtype=dataType)
    tout = np.array([], dtype=dataType)
    if ntspan > 2:
        tout = np.zeros((1, ntspan), dtype=dataType)
        yout = np.zeros((neq, ntspan), dtype=dataType)
    else:
        chunk = min(max(100, 50 * refine),
                    refine + math.floor(math.pow(2, 11) / neq))
        tout = np.zeros((1, chunk), dtype=dataType)
        yout = np.zeros((neq, chunk), dtype=dataType)

    nout = 1
    tout[nout - 1] = t
    yout[:, nout - 1] = y.copy()

    #Initialize method parameters
    stop = 0
    power = 1 / 5
    A = np.array([1. / 5., 3. / 10., 4. / 5., 8. / 9., 1., 1.], dtype=dataType)
    B = np.array([[
        1. / 5., 3. / 40., 44. / 45., 19372. / 6561., 9017. / 3168., 35. / 384.
    ], [0., 9. / 40., -56. / 15., -25360. / 2187., -355. / 33., 0.
        ], [0., 0., 32. / 9., 64448. / 6561., 46732. / 5247., 500. / 1113.],
                  [0., 0., 0., -212. / 729., 49. / 176., 125. / 192.],
                  [0., 0., 0., 0., -5103. / 18656., -2187. / 6784.],
                  [0., 0., 0., 0., 0., 11. / 84.], [0., 0., 0., 0., 0., 0.]],
                 dtype=dataType)

    E = np.array([[71. / 57600.], [0.], [-71. / 16695.], [71. / 1920.],
                  [-17253. / 339200.], [22. / 525.], [-1. / 40.]],
                 dtype=dataType)
    f = np.zeros((neq, 7), dtype=dataType)
    hmin = 16 * np.spacing(float(t))
    np.set_printoptions(precision=16)

    #Initial step
    if htry == 0:
        absh = min(hmax, htspan)
        if normcontrol:
            rh = (np.linalg.norm(f0) /
                  max(normy, threshold)) / (0.8 * math.pow(rtol, power))
        else:
            if isinstance(threshold, list):
                rh = np.linalg.norm(f0 / np.maximum(np.abs(y), threshold),
                                    np.inf) / (0.8 * math.pow(rtol, power))
            else:
                rh = np.linalg.norm(
                    f0 / np.maximum(np.abs(y), np.repeat(threshold, len(y))),
                    np.inf) / (0.8 * math.pow(rtol, power))
        if (absh * rh) > 1:
            absh = 1 / rh
        absh = max(absh, hmin)
    else:
        absh = min(hmax, max(hmin, htry))

    f[:, 0] = f0

    ynew = np.zeros(neq, dtype=dataType)

    #Main loop
    done = False
    while not done:
        hmin = 16 * np.spacing(float(t))
        absh = min(hmax, max(hmin, absh))
        h = tdir * absh

        #If next step is within 10% of finish
        if 1.1 * absh >= abs(tfinal - t):
            h = tfinal - t
            absh = abs(h)
            done = True

        #Advancing one step
        nofailed = True
        while True:
            hA = h * A
            hB = h * B
            f[:, 1] = feval(odeFcn, t + hA[0], y + np.matmul(f, hB[:, 0]),
                            odeArgs)
            f[:, 2] = feval(odeFcn, t + hA[1], y + np.matmul(f, hB[:, 1]),
                            odeArgs)
            f[:, 3] = feval(odeFcn, t + hA[2], y + np.matmul(f, hB[:, 2]),
                            odeArgs)
            f[:, 4] = feval(odeFcn, t + hA[3], y + np.matmul(f, hB[:, 3]),
                            odeArgs)
            f[:, 5] = feval(odeFcn, t + hA[4], y + np.matmul(f, hB[:, 4]),
                            odeArgs)

            tnew = t + hA[5]
            if done:
                tnew = tfinal  #Hit end point exactly
            h = tnew - t

            ynew = y + np.matmul(f, hB[:, 5])
            f[:, 6] = feval(odeFcn, tnew, ynew, odeArgs)
            nfevals = nfevals + 6

            #Estimation of the error
            NNrejectStep = False
            if normcontrol:
                normynew = np.linalg.norm(ynew)
                errwt = max(max(normy, normynew), threshold)
                err = absh * np.linalg.norm(np.matmul(f, E)[:, 0]) / errwt
                if nonNegative and err <= rtol and any(
                    [True for i in idxNonNegative if ynew[i] < 0]):
                    errNN = np.linalg.norm(
                        [max(0, -1 * ynew[i]) for i in idxNonNegative]) / errwt
                    if errNN > rtol:
                        err = errNN
                        NNrejectStep = True
            else:
                denom = np.maximum(np.maximum(np.abs(y), np.abs(ynew)),
                                   threshold)
                err = absh * np.linalg.norm(
                    np.divide(np.matmul(f, E)[:, 0], denom), np.inf)
                if nonNegative and err <= rtol and any(
                    [True for i in idxNonNegative if ynew[i] < 0]):
                    errNN = np.linalg.norm(
                        np.divide(
                            [max(0, -1 * ynew[i]) for i in idxNonNegative],
                            thresholdNonNegative), np.inf)
                    if errNN > rtol:
                        err = errNN
                        NNrejectStep = True

            #Error is outside the tolerance
            if err > rtol:
                nfailed = nfailed + 1
                if absh <= hmin:
                    warnings.warn("ode45: ode45: IntegrationTolNotMet " +
                                  str(t) + " " + str(hmin))
                    return odefinalize(solver_name, printstats,
                                       [nsteps, nfailed, nfevals], nout, tout,
                                       yout, haveEventFcn, teout, yeout, ieout)

                if nofailed:
                    nofailed = False
                    if NNrejectStep:
                        absh = max(hmin, 0.5 * absh)
                    else:
                        absh = max(
                            hmin,
                            absh * max(0.1, 0.8 * math.pow(rtol / err, power)))
                else:
                    absh = max(hmin, 0.5 * absh)
                h = tdir * absh
                done = False
            else:
                #Successful step
                NNreset_f7 = False
                if nonNegative and any(
                    [True for i in idxNonNegative if ynew[i] < 0]):
                    for j in idxNonNegative:
                        ynew[j] = max(ynew[j], 0)

                    if normcontrol:
                        normynew = np.linalg.norm(ynew)
                    NNreset_f7 = True

                break

        nsteps += 1

        if haveEventFcn:
            te, ye, ie, valt, stop = odezero([], eventFcn, eventArgs, valt, t,
                                             np.transpose(np.array([y])), tnew,
                                             np.transpose(np.array([ynew])),
                                             t0, h, f, idxNonNegative)
            if len(te) != 0:
                if len(teout) == 0:
                    teout = np.copy(te)
                else:
                    teout = np.append(teout, te)

                if len(yeout) == 0:
                    yeout = np.copy(ye)
                else:
                    yeout = np.append(yeout, ye, axis=1)

                if len(ieout) == 0:
                    ieout = np.copy(ie)
                else:
                    ieout = np.append(ieout, ie)

                if stop:
                    #Terminal event
                    taux = t + (te[-1] - t) * A
                    _, f[:, 1:7] = ntrp45(taux, t, np.transpose(np.array([y])),
                                          h, f, idxNonNegative)
                    tnew = te[-1]
                    ynew = ye[:, -1]
                    h = tnew - t
                    done = True

        if outputAt == "SolverSteps":
            #Computed points, no refinement
            nout_new = 1
            tout_new = np.array([tnew])
            yout_new = np.transpose(np.array([ynew]))
        elif outputAt == "RefinedSteps":
            #Computed points, with refinement
            tref = t + (tnew - t) * s
            nout_new = refine
            tout_new = tref.copy()
            tout_new = np.append(tout_new, tnew)
            yout_new, _ = ntrp45(tref, t, np.transpose(np.array([y])), h, f,
                                 idxNonNegative)
            yout_new = np.append(yout_new,
                                 np.transpose(np.array([ynew])),
                                 axis=1)
        elif outputAt == "RequestedPoints":
            #Chosen points
            nout_new = 0
            tout_new = np.array([])
            yout_new = np.array([])
            while nex <= ntspan:
                if tdir * (tnew - tspan[nex - 1]) < 0:
                    if haveEventFcn and stop:
                        nout_new = nout_new + 1
                        tout_new = np.append(tout_new, tnew)
                        if len(yout_new) == 0:
                            yout_new = np.transpose(np.array([ynew]))
                        else:
                            yout_new = np.append(yout_new,
                                                 np.transpose(np.array([ynew
                                                                        ])),
                                                 axis=1)
                    break

                nout_new = nout_new + 1
                tout_new = np.append(tout_new, tspan[nex - 1])

                if tspan[nex - 1] == tnew:
                    yout_temp = np.transpose(np.array([ynew]))
                else:
                    yout_temp, _ = ntrp45(tspan[nex - 1], t, y, h, f,
                                          idxNonNegative)

                if len(yout_new) == 0:
                    yout_new = yout_temp
                else:
                    yout_new = np.append(yout_new, yout_temp, axis=1)
                nex = nex + 1

        #Extra memory allocation
        if nout_new > 0:
            oldnout = nout
            nout = nout + nout_new
            if nout > len(tout[0]):
                talloc = np.zeros((1, chunk), dtype=dataType)
                tout = np.array([np.append(tout, talloc)])
                yalloc = np.zeros((neq, chunk), dtype=dataType)
                yout = np.append(yout, yalloc, axis=1)
            for i in range(oldnout, nout):
                tout[0, i] = tout_new[i - oldnout]
                yout[:, i] = yout_new[:, i - oldnout]

        if done:
            break

        #No failures, compute new h
        if nofailed:
            temp = 1.25 * math.pow((err / rtol), power)
            if temp > 0.2:
                absh = absh / temp
            else:
                absh = 5.0 * absh

        #Advance the integration by one step
        t = tnew
        y = ynew.copy()

        if normcontrol:
            normy = normynew

        if NNreset_f7:
            f[:, 6] = feval(odeFcn, tnew, ynew, odeArgs)
            nfevals = nfevals + 1
        f[:, 0] = f[:, 6]

    return odefinalize(solver_name, printstats, [nsteps, nfailed, nfevals],
                       nout, tout, yout, haveEventFcn, teout, yeout, ieout)
コード例 #14
0
def odezero(ntrpfun, eventfun, eventargs, v, t, y, tnew, ynew, t0, h, f,
            idxNonNegative):
    # Initialize.
    tol = 128 * np.maximum(np.finfo(float(t)).eps, np.finfo(float(tnew)).eps)
    tol = np.minimum(tol, np.abs(tnew - t))
    tout = np.array([])
    yout = np.array([[], []])
    iout = np.array([])

    tdir = np.sign(tnew - t)
    stop = False
    rmin = np.finfo(float).tiny

    # Set up tL, tR, yL, yR, vL, vR, isterminal and direction.
    tL = t
    yL = y
    vL = v
    [vnew, isterminal, direction] = feval(eventfun, tnew, ynew, eventargs)
    if len(direction) == 0:
        direction = np.zeros(len(vnew))  # zeros crossings in any direction
    tR = tnew
    yR = ynew
    vR = vnew

    # Initialize ttry so that we won't extrapolate if vL or vR is zero.
    ttry = tR

    # Find all events before tnew or the first terminal event.
    while True:
        lastmoved = 0
        while True:
            # Events of interest shouldn't have disappeared, but new ones might
            # be found in other elements of the v vector.
            indzc = [
                i for i in range(len(direction))
                if np.sign(vR[i]) != np.sign(vL[i]) and direction[i] *
                (vR[i] - vL[i]) >= 0
            ]
            if len(indzc) == 0:
                if lastmoved != 0:
                    raise Exception('ode45:odezero:LostEvent')
                else:
                    return tout, yout, iout, vnew, stop

            # Check if the time interval is too short to continue looking.
            delta = tR - tL
            if np.abs(delta) <= tol:
                break

            if (tL == t) and any(
                [vL[index] == 0 and vR[index] != 0 for index in indzc]):
                ttry = tL + tdir * 0.5 * tol

            else:
                #Compute Regula Falsi change, using leftmost possibility.
                change = 1
                for j in indzc:
                    # If vL or vR is zero, try using old ttry to extrapolate.
                    if vL[j] == 0:
                        if (tdir * ttry > tdir * tR) and (vtry[j] != vR[j]):
                            maybe = 1.0 - vR[j] * (ttry - tR) / (
                                (vtry[j] - vR[j]) * delta)
                            if (maybe < 0) or (maybe > 1):
                                maybe = 0.5
                        else:
                            maybe = 0.5
                    elif vR[j] == 0.0:
                        if (tdir * ttry < tdir * tL) and (vtry[j] != vL[j]):
                            maybe = vL[j] * (tL - ttry) / (
                                (vtry[j] - vL[j]) * delta)
                            if (maybe < 0) or (maybe > 1):
                                maybe = 0.5
                        else:
                            maybe = 0.5
                    else:
                        maybe = -vL[j] / (vR[j] - vL[j])  #Note vR(j) != vL(j).
                    if maybe < change:
                        change = maybe
                change = change * np.abs(delta)

                # Enforce minimum and maximum change.
                change = np.maximum(
                    0.5 * tol, np.minimum(change,
                                          np.abs(delta) - 0.5 * tol))
                ttry = tL + tdir * change

            # Compute vtry.
            ytry, trash1 = ntrp45(ttry, t, y, tnew, ynew, h, f, idxNonNegative)
            ytry = ytry[:, 0]
            [vtry, trash2, trash3] = feval(eventfun, ttry, ytry, eventargs)

            # Check for any crossings between tL and ttry.
            indzc = [
                i for i in range(len(direction))
                if np.sign(vtry[i]) != np.sign(vL[i]) and direction[i] *
                (vtry[i] - vL[i]) >= 0
            ]

            if (len(indzc) != 0):
                # Move right end of bracket leftward, remembering the old value.
                tswap = tR
                tR = ttry
                ttry = tswap
                yswap = yR
                yR = ytry
                ytry = yswap
                vswap = vR
                vR = vtry
                vtry = vswap
                # Illinois method.  If we've moved leftward twice, halve
                # vL so we'll move closer next time.
                if lastmoved == 2:
                    # Watch out for underflow and signs disappearing.
                    maybe = 0.5 * vL
                    i = [
                        j for j in range(len(maybe))
                        if np.abs(maybe[j] >= rmin)
                    ]
                    for temp in i:
                        vL[temp] = maybe[temp]

                lastmoved = 2
            else:
                #Move left end of bracket rightward, remembering the old value.
                tswap = tL
                tL = ttry
                ttry = tswap
                yswap = yL
                yL = ytry
                ytry = yswap
                vswap = vL
                vL = vtry
                vtry = vswap
                # Illinois method.  If we've moved rightward twice, halve
                # vR so we'll move closer next time.
                if lastmoved == 1:
                    # Watch out for underflow and signs disappearing.
                    maybe = 0.5 * vR
                    i = [
                        j for j in range(len(maybe))
                        if np.abs(maybe[j] >= rmin)
                    ]
                    for temp in i:
                        vR[temp] = maybe[temp]

                lastmoved = 1

        j = np.ones([len(indzc)])
        add_tout = np.array([tR for i in j])
        add_yout = np.tile(np.transpose(np.array([yR])), len(indzc))
        add_iout = np.transpose(np.array([indzc]))
        if len(tout) == 0:
            tout = add_tout
            yout = add_yout
            iout = add_iout
        else:
            tout = np.concatenate((tout, add_tout))
            yout = np.concatenate((yout, add_yout), axis=1)
            iout = np.concatenate((iout, add_iout))

        if any([isterminal[i] for i in indzc]):
            if tL != t0:
                stop = True
            break
        elif np.abs(tnew - tR) <= tol:
            #  We're not going to find events closer than tol.
            break
        else:
            # Shift bracket rightward from [tL tR] to [tR+0.5*tol tnew].
            ttry = tR
            ytry = yR
            vtry = vR
            tL = tR + tdir * 0.5 * tol
            yL, trash1 = ntrp45(tL, t, y, tnew, ynew, h, f, idxNonNegative)
            yL = yL[:, 0]
            [vL, trash2, trash3] = feval(eventfun, tL, yL, eventargs)
            tR = tnew
            yR = ynew
            vR = vnew

    return tout, yout, iout, vnew, stop
コード例 #15
0
def odearguments(FcnHandlesUsed, solver, ode, tspan, y0, options, extras):

    if FcnHandlesUsed:
        tspan = np.array(tspan)
        if tspan.size < 2:
            raise Exception("pyhton:odearguments:tspan.size < 2")

        htspan = np.abs(tspan[1] - tspan[0])
        tspan = np.array(tspan)
        ntspan = tspan.size
        t0 = tspan[0]
        NEXT = 1  # NEXT entry in tspan
        tfinal = tspan[ntspan - 1]
        args = extras

    y0 = np.array(y0)
    neq = len(y0)

    # Test that tspan is internally consistent.
    if any(np.isnan(tspan)):
        raise Exception("pyhton:odearguments:TspanNaNValues")
    if t0 == tfinal:
        raise Exception("pyhton:odearguments:TspanEndpointsNotDistinct")

    if tfinal > t0:
        tdir = 1
    else:
        tdir = -1

    if any(tdir * np.diff(tspan) <= 0):
        raise Exception("pyhton:odearguments:TspanNotMonotonic")

    f0 = feval(ode, t0, y0, args)

    if options is None:
        options = Odeoptions()  #Use default values

    if options.MaxStep is None:
        options.MaxStep = np.abs(0.1 * (tfinal - t0))

    rtol = np.array([options.RelTol])
    if (len(rtol) != 1 or rtol <= 0):
        raise Exception("pyhton:odearguments:RelTolNotPosScalar")
    if rtol < 100 * np.finfo(float).eps:
        rtol = 100 * np.finfo(float).eps

    atol = options.AbsTol
    if isinstance(atol, list):
        atol = np.array(atol)
    else:
        atol = np.array([atol])

    if any(atol <= 0):
        raise Exception("python:odearguments:AbsTolNotPos")

    normcontrol = options.NormControl
    if normcontrol:
        if len(atol) != 1:
            raise Exception("python:odearguments:NonScalarAbsTol")
        normy = np.linalg.norm(y0)
    else:
        if ((len(atol) != 1) and (len(atol) != neq)):
            raise Exception("python:odearguments:SizeAbsTol")
        normy = None

    threshold = atol / rtol

    hmax = np.array([options.MaxStep])
    if hmax <= 0:
        raise Exception("python:odearguments:MaxStepLEzero")

    htry = options.InitialStep
    if htry is not None:
        if htry <= 0:
            raise Exception("python:odearguments:InitialStepLEzero")

    odeFcn = ode
    dataType = 'float64'

    return neq, tspan, ntspan, NEXT, t0, tfinal, tdir, y0, f0, args, odeFcn, options, threshold, rtol, normcontrol, normy, hmax, htry, htspan, dataType
コード例 #16
0
ファイル: Bisect.py プロジェクト: M-Terry/pyfiles
def Bisect(fun, a, b, tol, maxIter):
    """
          Input and output variables
     fun       string containing name of function
     [a,b]     interval containing zero
     tol       allowable tolerance in computed zero
     maxIter   maximum number of iterations
     x         vector of approximations to zero
     y         vector of function values, fun(x)
    
    """
    A = np.empty([1, maxIter])
    B = np.empty([1, maxIter])
    x = np.empty([1, maxIter])
    y = np.empty([1, maxIter])
    ya = np.empty([1, maxIter])
    yb = np.empty([1, maxIter])
    A[0, 0] = a
    B[0, 0] = b
    ya[0, 0] = feval(fun, [A[0, 0]])
    yb[0, 0] = feval(fun, [B[0, 0]])
    if ya[0, 0] * yb[0, 0] > 0.0:
        print 'Function has same sign at end points'
        return

    for i in range(0, maxIter - 1):
        x[0, i] = (A[0, i] + B[0, i]) / 2
        y[0, i] = feval(fun, [x[0, i]])
        if (x[0, i] - A[0, i]) < tol:
            print 'Bisection method has converged'
            break
        elif y[0, i] == 0.0:
            print 'exact zero found'
            break
        elif y[0, i] * ya[0, i] < 0:
            A[0, i + 1] = A[0, i]
            ya[0, i + 1] = ya[0, i]
            B[0, i + 1] = x[0, i]
            yb[0, i + 1] = y[0, i]
        else:
            A[0, i + 1] = x[0, i]
            ya[0, i + 1] = y[0, i]
            B[0, i + 1] = B[0, i]
            yb[0, i + 1] = yb[0, i]

        iteration = i

    if (iteration >= maxIter):
        print 'zero not found to desired tolerance'

    n = i + 1
    k = np.linspace(1, n, n)
    out = np.zeros((n, 5))
    for i in range(n):
        out[i, 0] = k[i]
        out[i, 1] = A[0, i]
        out[i, 2] = B[0, i]
        out[i, 3] = x[0, i]
        out[i, 4] = y[0, i]
    np.set_printoptions(precision=16)
    print '  step        a         b          x          y'
    print out
    return out
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
 def local_odeFcn_nonnegative(t,y,*varargin):
     yp = feval(ode,t,y,varargin)
     ndx = [i for i in idxNonNegative if y[i]<=0]
     for i in ndx:
         yp[i] = max(yp[i],0)
     return yp
コード例 #19
0
def ode45_scipyStep(ode,tspan,y0,scipyStep,options = None, varargin = None) :
        
    solver_name = 'ode45'
    # Check inputs
    
    # Stats
    nsteps  = 0
    nfailed = 0
    nfevals = 0
      
    # Output
    FcnHandlesUsed  = isfunction(ode)
    if not FcnHandlesUsed :
        raise ValueError("ode is not an handle function")
    
    # Handle solver arguments
    neq, tspan, ntspan, NEXT, t0, tfinal, tdir, y0, f0, odeArgs, odeFcn, options, threshold, rtol, normcontrol, normy, hmax, htry, htspan, dataType = odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin)
    nfevals = nfevals + 1

    #Handle the output
    
    refine = np.maximum(1,options.Refine)
    
    if ntspan > 2 :
        outputAt = 1 # output only at tspan points
    elif refine <= 1 :
        outputAt = 2 # computed points, no refinement
    else :
        outputAt = 3 # computed points, with refinement
        S = np.array(range(1,refine))/refine

    # Handle the event function
    haveEventFcn,eventFcn,eventArgs,valt,teout,yeout,ieout = odeevents(FcnHandlesUsed,odeFcn,t0,y0,options,varargin)
    
    # Handle the mass matrix
    Mtype, M, Mfun = odemass(FcnHandlesUsed,odeFcn,t0,y0,options,varargin)
    if Mtype > 0 :
        #check if matrix is singular and raise an arror
        
        # Incorporate the mass matrix into odeFcn and odeArgs.
        odeFcn,odeArgs = odemassexplicit(FcnHandlesUsed,Mtype,odeFcn,odeArgs,Mfun,M)
        f0 = feval(odeFcn,t0,y0,odeArgs)
        nfevals = nfevals + 1
            
    #Non-negative solution components
    idxNonNegative = options.NonNegative
    nonNegative =  len(idxNonNegative) != 0
    #thresholdNonNegative = np.abs(threshold)
    if nonNegative :
        odeFcn,thresholdNonNegative,odeArgs = odenonnegative(odeFcn,y0,threshold,idxNonNegative,odeArgs)
        #odeArgs = (argSup,odeArgs)
        f0 = feval(odeFcn,t0,y0,odeArgs)
        nfevals = nfevals + 1
    
    t = t0
    y = y0
    
    # Allocate memory if we're generating output.
    
    if outputAt == 1 :
        output_y = np.zeros((neq,ntspan),dtype=dataType)
        output_t = np.zeros(ntspan,dtype=dataType)
    else :
        output_y = np.zeros((neq,1),dtype=dataType)
        output_t = np.zeros(1,dtype=dataType)
        
    output_y[:,0] = y0
    output_t[0] = t0
    
    #Initialize method parameters.
    POW = 1/5
    A = np.array([1/5, 3/10, 4/5, 8/9, 1, 1],dtype=dataType)
    B = np.array([
    [1/5, 3/40, 44/45, 19372/6561, 9017/3168, 35/384],
    [0, 9/40, -56/15, -25360/2187, -355/33, 0],
    [0, 0, 32/9, 64448/6561, 46732/5247, 500/1113],
    [0, 0, 0, -212/729, 49/176, 125/192],
    [0, 0, 0, 0, -5103/18656, -2187/6784],
    [0, 0, 0, 0, 0, 11/84],
    [0, 0, 0, 0, 0, 0]
    ],dtype=dataType)
    
    E = np.array([71/57600, 0, -71/16695, 71/1920, -17253/339200, 22/525, -1/40],dtype=dataType)
    f = np.zeros((neq,7),dtype=dataType)
    hmin = 16*np.finfo(float(t)).eps
    
    if htry is None :  # Compute an initial step size h using y'(t).
        absh = np.minimum(hmax, htspan)
        if normcontrol :
            rh = (np.linalg.norm(f0) / np.maximum(normy,threshold)) / (0.8 * rtol**POW)
        else :
            rh = np.linalg.norm(f0 / np.maximum(np.abs(y0),threshold),np.inf) / (0.8 * rtol**POW)
        if absh * rh > 1 :
            absh = 1 / rh
        absh = np.maximum(absh, hmin)
    else :
        absh = np.minimum(hmax, np.maximum(hmin, htry))
    f[:,0] = f0
    #THE MAIN LOOP
    done = False
    stop = False
    
    plop = 0
    while not done :
        
        h = scipyStep[plop]
        plop = plop +1
        absh = h
        # Stretch the step if within 10% of tfinal-t.
        if plop >= len(scipyStep) :
            done = True
   
        # LOOP FOR ADVANCING ONE STEP.
        nofailed = True  # no failed attempts
        
        while True :
                     
            hA = h * A
            hB = h * B

            f[:,1] = feval(odeFcn,t+hA[0],y+np.dot(f,hB[:,0]),odeArgs)
            f[:,2] = feval(odeFcn,t+hA[1],y+np.dot(f,hB[:,1]),odeArgs)
            f[:,3] = feval(odeFcn,t+hA[2],y+np.dot(f,hB[:,2]),odeArgs)
            f[:,4] = feval(odeFcn,t+hA[3],y+np.dot(f,hB[:,3]),odeArgs)
            f[:,5] = feval(odeFcn,t+hA[4],y+np.dot(f,hB[:,4]),odeArgs)
            
            tnew = t + hA[5]
            if done :
                tnew = tfinal  # Hit end point exactly.
            h = tnew - t # Purify h
            
            ynew = y + np.dot(f,hB[:,5])
            f[:,6] = feval(odeFcn,tnew,ynew,odeArgs)
            nfevals = nfevals + 6

            #else : # Successful step
            NNreset_f7 = False
            if nonNegative and np.any(ynew[idxNonNegative]<0) :
                ynew[idxNonNegative] = np.maximum(ynew[idxNonNegative],0)
                if normcontrol :
                    normynew = np.linalg.norm(ynew)
                NNreset_f7 = True
            break
        nsteps = nsteps + 1
             
        if haveEventFcn :
            te,ye,ie,valt,stop=odezero(None,eventFcn,eventArgs,valt,t,y,tnew,ynew,t0,h,f,idxNonNegative)
            
            if len(te) != 0 :
                
                teout=np.append(teout,te)
                if len(yeout) ==0 :
                    yeout=ye
                else:
                    yeout=np.append(yeout,ye,axis=1)
                ieout=np.append(ieout,ie)
                
                if stop :
                    taux = t + (te[-1] - t)*A
                    trash, f[:,1:7]=ntrp45(taux,t,y,None,None,h,f,idxNonNegative)
                    tnew = te[-1]
                    ynew = ye[:,-1]
                    h = tnew - t
                    done = True

        #GERER LES output
        if outputAt == 1 : #Evaluate only at t_span
            
            if tdir == 1 : #tspan is increasing
                while NEXT < ntspan :
                    if tspan[NEXT] == tnew :
                        
                        output_t[NEXT] = tnew     
                        output_y[:,NEXT] = ynew                       
                        NEXT = NEXT+1
                        
                    elif tspan[NEXT] < tnew and t < tspan[NEXT] :
                        
                        first_indice = NEXT
                        NEXT = NEXT+1
                        while tspan[NEXT] < tnew :
                            NEXT = NEXT+1
                        last_indice = NEXT
                        
                        tinterp = tspan[first_indice:last_indice]
                        output_t[first_indice:last_indice] = tinterp
                        
                        yinterp = ntrp45(tinterp,t,y,tnew,ynew,h,f,idxNonNegative,Need_ypinterp = False)
                        output_y[:,first_indice:last_indice] = yinterp
                        
                    elif stop == True :
                        output_t = np.append(output_t,[tnew],axis=0)
                        
                        to_concatenate_y = np.transpose(np.array([ynew]))
                        output_y = np.append(output_y,to_concatenate_y,axis=1)
                        
                        break
                        
                    elif tspan[NEXT] > tnew:
                        break
                    
            elif tdir == -1 : #tspan is decreasing
                while NEXT < ntspan :
                    if tspan[NEXT] == tnew :
                        
                        output_t[NEXT] = tnew
                        output_y[:,NEXT] = ynew
                        NEXT = NEXT+1
                        
                    elif tspan[NEXT] > tnew and t > tspan[NEXT] :
                        
                        first_indice = NEXT
                        NEXT = NEXT+1
                        while tspan[NEXT] > tnew :
                            NEXT = NEXT+1
                        last_indice = NEXT
                        
                        tinterp = tspan[first_indice:last_indice]
                        output_t[first_indice:last_indice] = tinterp
                        
                        yinterp = ntrp45(tinterp,t,y,tnew,ynew,h,f,idxNonNegative,Need_ypinterp = False)
                        output_y[:,first_indice:last_indice] = yinterp
                        
                    elif stop == True : # DEBUG
                        output_t = np.append(output_t,[tnew],axis=0)
                        
                        to_concatenate_y = np.transpose(np.array([ynew]))
                        output_y = np.append(output_y,to_concatenate_y,axis=1)
                        
                        break
                    
                    elif tspan[NEXT] < tnew:
                        break
        
        else : 
            if outputAt == 3 : #Evaluate at solver steps + refined step
                    
                tinterp = t + h*S               
                output_t = np.append(output_t,tinterp,axis=0)
                
                yinterp = ntrp45(tinterp,t,y,tnew,ynew,h,f,idxNonNegative,Need_ypinterp = False)
                output_y = np.append(output_y,yinterp,axis=1)
                
                output_t = np.append(output_t,[tnew],axis=0)
                
                to_concatenate_y = np.transpose(np.array([ynew]))
                
                output_y = np.append(output_y,to_concatenate_y,axis=1)               
                
            else : #Evaluate only at solver steps
                output_t = np.append(output_t,[tnew],axis=0)
                    
                to_concatenate_y = np.transpose(np.array([ynew]))
                output_y = np.append(output_y,to_concatenate_y,axis=1)
                
        
        if done :
            break
        
        # Advance the integration one step.
        t = tnew
        y = ynew
        if normcontrol:
            normy = normynew
            
        if NNreset_f7 :
        # Used f7 for unperturbed solution to interpolate.  
        # Now reset f7 to move along constraint. 
            f[:,6] = feval(odeFcn,tnew,ynew,odeArgs)
            nfevals = nfevals + 1
        f[:,0] = f[:,6]
        
    extdata = Extdata(odeFcn,options,odeArgs)
    stats = Stats(nsteps,nfailed,nfevals)
    oderesult = Oderesult(solver_name,extdata,output_t,output_y,stats,teout,yeout,ieout)
    return oderesult
コード例 #20
0
def ExplicitSolverHandleMass(t,y,odeFcn,massFcn,varargin = None) :
    A = feval(massFcn,t,y,varargin)
    b = feval(odeFcn,t,y,varargin)
    yp = np.linalg.lstsq(A, b,rcond=None)[0]

    return yp
コード例 #21
0
ファイル: ode45.py プロジェクト: armoreau/master-thesis
def ode45(ode, tspan, y0, options=None, varargin=None):

    solver_name = 'ode45'
    # Check inputs

    # Stats
    nsteps = 0
    nfailed = 0
    nfevals = 0

    # Output
    FcnHandlesUsed = isfunction(ode)
    if not FcnHandlesUsed:
        raise ValueError("ode is not an handle function")

    # Handle solver arguments
    neq, tspan, ntspan, NEXT, t0, tfinal, tdir, y0, f0, odeArgs, odeFcn, options, threshold, rtol, normcontrol, normy, hmax, htry, htspan, dataType = odearguments(
        FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin)
    nfevals = nfevals + 1

    #Handle the output
    refine = np.maximum(1, options.Refine)

    if ntspan > 2:
        outputAt = 1  # output only at tspan points
    elif refine <= 1:
        outputAt = 2  # computed points, no refinement
    else:
        outputAt = 3  # computed points, with refinement
        S = np.array(range(1, refine)) / refine

    # Handle the event function
    haveEventFcn, eventFcn, eventArgs, valt, teout, yeout, ieout = odeevents(
        FcnHandlesUsed, odeFcn, t0, y0, options, varargin)

    # Handle the mass matrix
    Mtype, M, Mfun = odemass(FcnHandlesUsed, odeFcn, t0, y0, options, varargin)
    if Mtype > 0:
        # Incorporate the mass matrix into odeFcn and odeArgs.
        odeFcn, odeArgs = odemassexplicit(FcnHandlesUsed, Mtype, odeFcn,
                                          odeArgs, Mfun, M)
        f0 = feval(odeFcn, t0, y0, odeArgs)
        nfevals = nfevals + 1

    #Non-negative solution components
    nonNegative = len(
        options.NonNegative) != 0  #not isempty(options.NonNegative)
    idxNonNegative = np.array(options.NonNegative)
    if nonNegative:
        odeFcn, thresholdNonNegative, odeArgs = odenonnegative(
            odeFcn, y0, threshold, idxNonNegative, odeArgs)
        f0 = feval(odeFcn, t0, y0, odeArgs)
        nfevals = nfevals + 1

    t = t0
    y = y0

    # Allocate memory for generating output.
    if outputAt == 1:
        output_y = np.zeros((neq, ntspan), dtype=dataType)
        output_t = np.zeros(ntspan, dtype=dataType)
    else:
        output_y = np.zeros((neq, 1), dtype=dataType)
        output_t = np.zeros(1, dtype=dataType)

    output_y[:, 0] = y0
    output_t[0] = t0

    #Initialize method parameters.
    POW = 1 / 5
    A = np.array([1 / 5, 3 / 10, 4 / 5, 8 / 9, 1, 1], dtype=dataType)
    B = np.array(
        [[1 / 5, 3 / 40, 44 / 45, 19372 / 6561, 9017 / 3168, 35 / 384],
         [0, 9 / 40, -56 / 15, -25360 / 2187, -355 / 33, 0],
         [0, 0, 32 / 9, 64448 / 6561, 46732 / 5247, 500 / 1113],
         [0, 0, 0, -212 / 729, 49 / 176, 125 / 192],
         [0, 0, 0, 0, -5103 / 18656, -2187 / 6784], [0, 0, 0, 0, 0, 11 / 84],
         [0, 0, 0, 0, 0, 0]],
        dtype=dataType)

    E = np.array([
        71 / 57600, 0, -71 / 16695, 71 / 1920, -17253 / 339200, 22 / 525,
        -1 / 40
    ],
                 dtype=dataType)
    f = np.zeros((neq, 7), dtype=dataType)
    hmin = 16 * np.finfo(float(t)).eps

    if htry is None:  # Compute an initial step size h using y'(t).
        absh = np.minimum(hmax, htspan)
        if normcontrol:
            rh = (np.linalg.norm(f0) /
                  np.maximum(normy, threshold)) / (0.8 * rtol**POW)
        else:
            rh = np.linalg.norm(f0 / np.maximum(np.abs(y0), threshold),
                                np.inf) / (0.8 * rtol**POW)
        if absh * rh > 1:
            absh = 1 / rh
        absh = np.maximum(absh, hmin)
    else:
        absh = np.minimum(hmax, np.maximum(hmin, htry))
    f[:, 0] = f0
    #THE MAIN LOOP
    done = False
    stop = False
    while not done:
        # By default, hmin is a small number such that t+hmin is only slightly
        # different than t.  It might be 0 if t is 0.
        hmin = 16 * np.finfo(float(t)).eps
        absh = np.minimum(hmax, np.maximum(
            hmin, absh))  # couldn't limit absh until new hmin
        h = tdir * absh

        # Stretch the step if within 10% of tfinal-t.
        if 1.1 * absh >= np.abs(tfinal - t):
            h = tfinal - t
            absh = np.abs(h)
            done = True

        # LOOP FOR ADVANCING ONE STEP.
        nofailed = True  # no failed attempts
        while True:

            hA = h * A
            hB = h * B

            f[:, 1] = feval(odeFcn, t + hA[0], y + np.dot(f, hB[:, 0]),
                            odeArgs)
            f[:, 2] = feval(odeFcn, t + hA[1], y + np.dot(f, hB[:, 1]),
                            odeArgs)
            f[:, 3] = feval(odeFcn, t + hA[2], y + np.dot(f, hB[:, 2]),
                            odeArgs)
            f[:, 4] = feval(odeFcn, t + hA[3], y + np.dot(f, hB[:, 3]),
                            odeArgs)
            f[:, 5] = feval(odeFcn, t + hA[4], y + np.dot(f, hB[:, 4]),
                            odeArgs)

            tnew = t + hA[5]
            if done:
                tnew = tfinal  # Hit end point exactly.
            h = tnew - t  # Purify h

            ynew = y + np.dot(f, hB[:, 5])
            f[:, 6] = feval(odeFcn, tnew, ynew, odeArgs)
            nfevals = nfevals + 6

            #Estimate the error
            NNrejectStep = False
            if normcontrol:
                normynew = np.linalg.norm(ynew)
                errwt = np.maximum(np.maximum(normy, normynew), threshold)
                err = absh * (np.linalg.norm(np.dot(f, E)) / errwt)
                if nonNegative and (err <= rtol) and np.any(
                        ynew[idxNonNegative] < 0):
                    errNN = np.linalg.norm(np.maximum(
                        0, -ynew[idxNonNegative])) / errwt
                    if errNN > rtol:
                        err = errNN
                        NNrejectStep = True
            else:
                err = absh * (np.linalg.norm(
                    np.dot(f, E) /
                    np.maximum(np.maximum(np.abs(y), np.abs(ynew)), threshold),
                    np.inf))
                if nonNegative and (err <= rtol) and np.any(
                        ynew[idxNonNegative] < 0):
                    errNN = np.linalg.norm(
                        np.maximum(0, -ynew[idxNonNegative]) /
                        thresholdNonNegative, np.inf)
                    if errNN > rtol:
                        err = errNN
                        NNrejectStep = True

            # Accept the solution only if the weighted error is no more than the
            # tolerance rtol.  Estimate an h that will yield an error of rtol on
            # the next step or the next try at taking this step, as the case may be,
            # and use 0.8 of this value to avoid failures.
            if err > rtol:  # Failed step
                nfailed = nfailed + 1
                if absh <= hmin:
                    print(
                        "Warning:python:ode45:IntegrationTolNotMet:absh <= hmin "
                    )
                    extdata = Extdata(odeFcn, options, odeArgs)
                    stats = Stats(nsteps, nfailed, nfevals)
                    oderesult = Oderesult(solver_name, extdata, output_t,
                                          output_y, stats, teout, yeout, ieout)
                    return oderesult

                if nofailed:
                    nofailed = False
                    if NNrejectStep:
                        absh = np.maximum(hmin, 0.5 * absh)
                    else:
                        absh = np.maximum(
                            hmin,
                            absh * np.maximum(0.1, 0.8 * (rtol / err)**POW))
                else:
                    absh = np.maximum(hmin, 0.5 * absh)
                h = tdir * absh
                done = False

            else:  # Successful step
                NNreset_f7 = False
                if nonNegative and np.any(ynew[idxNonNegative] < 0):
                    ynew[idxNonNegative] = np.maximum(ynew[idxNonNegative], 0)
                    if normcontrol:
                        normynew = np.linalg.norm(ynew)
                    NNreset_f7 = True
                break
        nsteps = nsteps + 1

        if haveEventFcn:
            te, ye, ie, valt, stop = odezero(None, eventFcn, eventArgs, valt,
                                             t, y, tnew, ynew, t0, h, f,
                                             idxNonNegative)

            if len(te) != 0:

                teout = np.append(teout, te)
                if len(yeout) == 0:
                    yeout = ye
                else:
                    yeout = np.append(yeout, ye, axis=1)
                ieout = np.append(ieout, ie)

                if stop:
                    taux = t + (te[-1] - t) * A
                    trash, f[:, 1:7] = ntrp45(taux, t, y, None, None, h, f,
                                              idxNonNegative)
                    tnew = te[-1]
                    ynew = ye[:, -1]
                    h = tnew - t
                    done = True

        #Manage output
        if outputAt == 1:  #Evaluate only at t_span

            if tdir == 1:  #tspan is increasing
                while NEXT < ntspan:
                    if tspan[NEXT] == tnew:

                        output_t[NEXT] = tnew
                        output_y[:, NEXT] = ynew
                        NEXT = NEXT + 1

                    elif tspan[NEXT] < tnew and t < tspan[NEXT]:

                        first_indice = NEXT
                        NEXT = NEXT + 1
                        while tspan[NEXT] < tnew:
                            NEXT = NEXT + 1
                        last_indice = NEXT

                        tinterp = tspan[first_indice:last_indice]
                        output_t[first_indice:last_indice] = tinterp

                        yinterp = ntrp45(tinterp,
                                         t,
                                         y,
                                         tnew,
                                         ynew,
                                         h,
                                         f,
                                         idxNonNegative,
                                         Need_ypinterp=False)
                        output_y[:, first_indice:last_indice] = yinterp

                    elif stop == True:
                        output_t = np.append(output_t, [tnew], axis=0)

                        to_concatenate_y = np.transpose(np.array([ynew]))
                        output_y = np.append(output_y,
                                             to_concatenate_y,
                                             axis=1)

                        break

                    elif tspan[NEXT] > tnew:
                        break

            elif tdir == -1:  #tspan is decreasing
                while NEXT < ntspan:
                    if tspan[NEXT] == tnew:

                        output_t[NEXT] = tnew
                        output_y[:, NEXT] = ynew
                        NEXT = NEXT + 1

                    elif tspan[NEXT] > tnew and t > tspan[NEXT]:

                        first_indice = NEXT
                        NEXT = NEXT + 1
                        while tspan[NEXT] > tnew:
                            NEXT = NEXT + 1
                        last_indice = NEXT

                        tinterp = tspan[first_indice:last_indice]
                        output_t[first_indice:last_indice] = tinterp

                        yinterp = ntrp45(tinterp,
                                         t,
                                         y,
                                         tnew,
                                         ynew,
                                         h,
                                         f,
                                         idxNonNegative,
                                         Need_ypinterp=False)
                        output_y[:, first_indice:last_indice] = yinterp

                    elif stop == True:  # DEBUG
                        output_t = np.append(output_t, [tnew], axis=0)

                        to_concatenate_y = np.transpose(np.array([ynew]))
                        output_y = np.append(output_y,
                                             to_concatenate_y,
                                             axis=1)

                        break

                    elif tspan[NEXT] < tnew:
                        break

        else:
            if outputAt == 3:  #Evaluate at solver steps + refined step

                tinterp = t + h * S
                output_t = np.append(output_t, tinterp, axis=0)

                yinterp = ntrp45(tinterp,
                                 t,
                                 y,
                                 tnew,
                                 ynew,
                                 h,
                                 f,
                                 idxNonNegative,
                                 Need_ypinterp=False)
                output_y = np.append(output_y, yinterp, axis=1)

                output_t = np.append(output_t, [tnew], axis=0)

                to_concatenate_y = np.transpose(np.array([ynew]))

                output_y = np.append(output_y, to_concatenate_y, axis=1)

            else:  #Evaluate only at solver steps
                output_t = np.append(output_t, [tnew], axis=0)

                to_concatenate_y = np.transpose(np.array([ynew]))
                output_y = np.append(output_y, to_concatenate_y, axis=1)

        if done:
            break
        # If there were no failures compute a new h.
        if nofailed:
            # Note that absh may shrink by 0.8, and that err may be 0.
            temp = 1.25 * (err / rtol)**POW
            if temp > 0.2:
                absh = absh / temp
            else:
                absh = 5.0 * absh
        # Advance the integration one step.
        t = tnew
        y = ynew
        if normcontrol:
            normy = normynew

        if NNreset_f7:
            # Used f7 for unperturbed solution to interpolate.
            # Now reset f7 to move along constraint.
            f[:, 6] = feval(odeFcn, tnew, ynew, odeArgs)
            nfevals = nfevals + 1
        f[:, 0] = f[:, 6]

    extdata = Extdata(odeFcn, options, odeArgs)
    stats = Stats(nsteps, nfailed, nfevals)
    oderesult = Oderesult(solver_name, extdata, output_t, output_y, stats,
                          teout, yeout, ieout)
    return oderesult
コード例 #22
0
def odezero(ntrpfun, eventfun, eventargs, v, t, y, tnew, ynew, t0, h, f,
            idxNonNegative):
    '''Helper function to find the zero crossings of the event function for ode45.
        
    Parameters
    ----------
    ntrpfun : callable
        ntrp45
    eventfun : callable
        Event function to be evaluated.
    eventargs : array_like
        Extra arguments for the event function.
    v : array_like
        Previously evaluated event function.
    t : scalar
        Current time.
    y : array_like, shape(n,)
        Currently evaluated points.
    tnew : scalar
        Next time.
    ynew : array_like, shape(n,)
        Next evaluated points. 
    t0 : float
        Final time interval.
    h : scalar
        Size of step.
    f : ndarray, shape(n,7)
        Evaluated derivative points.
    idxNonNegative : array_like, shape(m,)
        Non negative solutions.
        
        
    Returns
    -------
    tout : array_like
        Time of events.
    yout : array_like
        Evaluated points of events.
    iout : array_like
        Index of events.
    vnew : array_like
        New evaluation of the event function.
    stop : Boolean
        Whether execution should be halted.
    '''

    #Initialize
    tol = 128 * max(np.spacing(float(t)), np.spacing(float(tnew)))
    tol = min(tol, abs(tnew - t))

    tout = np.array([])
    yout = np.array([])
    iout = np.array([])
    tdir = math.copysign(1, tnew - t)
    stop = 0
    rmin = np.finfo(float).tiny

    tL = t
    yL = np.array(y)
    vL = v

    [vnew, isterminal, direction] = feval(eventfun, tnew, ynew, eventargs)

    if len(direction) == 0:
        direction = np.zeros(len(vnew))

    tR = tnew
    yR = np.array(ynew)
    vR = vnew
    ttry = tR

    #Find all events
    while True:
        lastmoved = 0
        while True:

            indzc = [
                i for i in range(len(direction))
                if (direction[i] * (vR[i] - vL[i]) >= 0) and (
                    vR[i] * vL[i] < 0 or vR[i] * vL[i] == 0)
            ]
            if len(indzc) == 0:
                if lastmoved != 0:
                    raise Exception('ode45:odezero:LostEvent')
                return tout, yout, iout, vnew, stop

            #Verify interval is still large enough
            delta = tR - tL
            if abs(delta) <= tol:
                break

            if (tL == t) and any(
                [vL[index] == 0 and vR[index] != 0 for index in indzc]):
                ttry = tL + tdir * 0.5 * tol
            else:
                #Regula Falsi method
                change = 1
                for j in indzc:
                    if vL[j] == 0:
                        if (tdir * ttry > tdir * tR) and (vtry[j] != vR[j]):
                            maybe = 1.0 - float(vR[j] * (ttry - tR) /
                                                ((vtry[j] - vR[j]) * delta))
                            if (maybe < 0) or (maybe > 1):
                                maybe = 0.5
                        else:
                            maybe = 0.5
                    elif vR[j] == 0.0:
                        if (tdir * ttry < tdir * tL) and (vtry[j] != vL[j]):
                            maybe = float(vL[j] * (tL - ttry) /
                                          ((vtry[j] - vL[j]) * delta))
                            if (maybe < 0) or (maybe > 1):
                                maybe = 0.5
                        else:
                            maybe = 0.5
                    else:
                        maybe = float(-vL[j] / (vR[j] - vL[j]))
                    if maybe < change:
                        change = maybe
                change = change * abs(delta)

                change = max(0.5 * tol, min(change, abs(delta) - 0.5 * tol))
                ttry = tL + tdir * change

            ytry, discard = ntrp45(ttry, t, y, h, f, idxNonNegative)
            [vtry, discrad1, discard2] = feval(eventfun, ttry, ytry, eventargs)
            indzc = [
                i for i in range(len(direction))
                if (direction[i] * (vtry[i] - vL[i]) >= 0) and (
                    vtry[i] * vL[i] < 0 or vtry[i] * vL[i] == 0)
            ]

            #Illinois Method
            if len(indzc) != 0:
                tswap = tR
                tR = ttry
                ttry = tswap
                yswap = yR
                yR = ytry
                ytry = yswap
                vswap = vR
                vR = vtry
                vtry = vswap
                if lastmoved == 2:
                    maybe1 = [0.5 * x for x in vL]
                    for i in range(len(maybe1)):
                        if abs(maybe1[i]) >= rmin:
                            vL[i] = maybe1[i]
                lastmoved = 2
            else:
                tswap = tL
                tL = ttry
                ttry = tswap
                yswap = yL
                yL = ytry
                ytry = yswap
                vswap = vL
                vL = vtry
                vtry = vswap

                if lastmoved == 1:
                    maybe2 = [0.5 * x for x in vR]
                    for i in range(len(maybe2)):
                        if abs(maybe2[i]) >= rmin:
                            vR[i] = maybe2[i]

                lastmoved = 1

        ntout = np.array([tR for index in range(len(indzc))])
        nyout = np.tile(np.transpose([yR]), len(indzc))[0]
        niout = np.array([indzc[index] for index in range(len(indzc))])
        if len(tout) == 0:
            tout = ntout
            yout = nyout
            iout = niout
        else:
            tout = np.append(tout, ntout)
            yout = np.append(yout, nyout, axis=1)
            iout = np.append(iout, niout)

        if any([isterminal[index] == 1 for index in indzc]):
            if tL != t0:
                stop = 1
            return tout, yout, iout, vnew, stop
        elif abs(tnew - tR) <= tol:
            #Found acceptable solution
            break
        else:
            #Shift bracket rightward
            ttry = tR
            ytry = yR
            vtry = vR
            tL = tR + tdir * 0.5 * tol
            yL, discard = ntrp45(tL, t, y, h, f, idxNonNegative)
            [vL, discard1, discard2] = feval(eventfun, tL, yL, eventargs)
            tR = tnew
            yR = ynew
            vR = vnew
    return tout, yout, iout, vnew, stop
コード例 #23
0
def odemass(t0, y0, options, extras):
    '''Mass helper function for ode45.
        
    Parameters
    ----------
    t0 : scalar
        Initial time to be evaluated.
    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
    -------
    massType : integer
        0 : If no mass option exists in options.
        1 : If mass option exists in options, and it matrix.
        2 : If mass option exists in options, and it is time-dependent function.
        2 : If mass option exists in options, and it is statetime-dependent function.
    massM : array_like, shape(n,n) || None
        Mass matrix if the mass option exists in options, and it is matrix. If mass option is a function
        then it is the evaluated mass function with the initial values. None otherwise.
    massFcn : callable || None
        Mass function if the mass option exists in options, and it is function. None otherwise.
    '''

    #Initialize
    massType = 0
    massFcn = None
    massM = sp.eye(len(y0), format="csr")
    massArgs = None

    Moption = odeget(options, 'Mass', None)
    if isinstance(Moption, type(None)):
        #No mass option
        return massType, massM, massFcn

    elif not callable(Moption):
        #Mass matrix
        massType = 1
        massM = Moption
        return massType, massM, massFcn

    else:
        #Mass function
        massFcn = Moption
        massArgs = extras
        Mstdep = odeget(options, 'MStateDependence', 'weak')

        if Mstdep == 'none':
            massType = 2
        elif Mstdep == 'weak':
            massType = 3
        else:
            raise ValueError(
                'odemass: MStateDependenceMass: Wrong type for MStateDependenceMass'
            )

        if massType > 2:
            massM = feval(massFcn, t0, y0, massArgs)
        else:
            massM = feval(massFcn, t0, None, massArgs)

    return massType, massM, massFcn