Untitled

 avatar
unknown
python
3 years ago
6.8 kB
5
Indexable
from functools import total_ordering
import numpy as np
import matplotlib.pyplot as plt
from scipy.linalg import expm
from scipy import integrate

a = 3
b = 9
c = 15
d = 15

lamb = 1
def testeq(_,u): #
    l = np.array([[lamb]])
    return l*u

def testeqnbr(_,u): #
    return lamb*u

def solution(y0, tg):
    l = np.array([[lamb]])
    return np.array([np.dot(np.exp(l*t), y0) for t in tg])

def RK34Step(f, told, uold, h):
    unew = RK4Step(f, told, uold, h)
    hY1 = h*f(told,uold)
    hY2 = h*f(told+h/2, uold+hY1/2)
    hY3 = h*f(told+h/2, uold+hY2/2)
    hY4 = h*f(told+h, uold+hY3)
    hZ3 = h* f(told + h, uold - hY1 + 2*hY2)
    err = (2*hY2 + hZ3 -2*hY3 - hY4)/6
    return [unew, err]
    

def RK4Step(f, told, uold, h): #f är lambdauttryck motsvarande, tar in 2 parametrar
    hY1 = h*f(told,uold)
    hY2 = h*f(told+h/2, uold+hY1/2)
    hY3 = h*f(told+h/2, uold+hY2/2)
    hY4 = h*f(told+h, uold+hY3)
    return uold + (hY1 + 2*hY2 + 2*hY3 + hY4)/6

def newstep(tol, err, errold, hold, k):
    return ( (tol/abs(err))**(2/(3*k)) * (tol/abs(errold))**(-1/(3*k)) )*hold

def adaptiveRK34(f, t0, tf, y0, tol):
    t = [t0]
    y = [y0]
    
    tn = t0
    yn = y0
    rn = tol
    hm = abs(tf-t0)*np.power(tol, 1/4)/(100*(1 + np.linalg.norm(f(None, y0))))
    nbrSteps = 0
    while(hm < tf - tn):
        yn, err = RK34Step(f, tn, yn, hm)
        tn= tn+hm

        t.append(tn) 
        y.append(yn)
        
        rold = rn
        rn = np.linalg.norm(err)
        hm = newstep(tol, rn, rold, hm, 4)
        nbrSteps += 1

    t.append(tf) 
    y.append(RK34Step(f, tn, yn, tf - tn)[0] )
    nbrSteps += 1
    return [np.array(t), np.array(y), nbrSteps]

def RK4Solve(f, t0, tf, y0, N):
    tg = np.linspace(t0,tf,N+1)
    h =(tf-t0)/N
    approx=np.array([y0])
    yn = y0
    tn = t0
    for _ in range(N):
        yn = RK4Step(f, tn, yn, h)
        tn = tn+h
        approx = np.append(approx, yn)
   
    err = solution(y0, tg) - approx
    return [tg, approx, err]

def lotkaVolterraSolver():
    u_f0 = np.array([1,1])
    u2_f0 = np.array([1.7, 0.1])
    tol = 1e-7
    tmax = 100
    lotka = lambda t, u: np.array([a*u[0] - b*u[0]*u[1], c*u[0]*u[1] - d*u[1] ])
    [t, y, _] = adaptiveRK34(lotka, 0, tmax, u_f0, tol)
    [t2, y2, _] = adaptiveRK34(lotka, 0 , tmax, u2_f0, tol)

    title = "Solution to initial condition over time t with u_f0 = [ "
    add = ",".join(str(x) for x in u_f0)
    add2 = ",".join(str(x) for x in u2_f0)

    figure, axis = plt.subplots(2,2)
    axis[0, 0].plot(t, y)
    axis[0, 0].set_title(title + add + " ]")

    axis[0, 1].plot(y[:,0], y[:,1], 'm')
    axis[0, 1].set_title("Phase portrait when u_f0 = [ " + add + " ]")

    axis[1, 0].plot(t2, y2)
    axis[1, 0].set_title(title + add2 + " ]")

    axis[1, 1].plot(y2[:,0], y2[:,1], 'm')
    axis[1, 1].set_title("Phase portrait when u_f0 = [ " + add2 + " ]")
    plt.show()

    plt.figure(2)
    plt.title("H:s change over time")
    plt.semilogy(t, [abs(H(u ,a ,b ,c ,d)/H(u_f0 , a, b ,c ,d) - 1) for u in y], 'r')
    plt.show()

def H(u, *parameters):
    x, y = u
    a, b, c, d = parameters
    sol = c*x + b*y - d*np.log(x) - a*np.log(y)
    return sol
    
def errVSh(f, t0, tf, y0):
    nbr = 11
    N = 2**np.linspace(1, nbr, num=nbr, dtype=int)
    h = np.divide(tf-t0, N)
    E = []
    for n in N:
        _, _, err = RK4Solve(f,t0,tf,y0,n)
        E.append(np.linalg.norm(err[-1][-1])) #ska vara två [][] för matris!!!!!!!!
    plt.figure(1)
    plt.loglog(h,E)
    plt.loglog(h, h**4)
    plt.title("Error plot")
    plt.show()

def task1Solver():
     y0 = np.array([1])
     t0 = 0
     tf = 1
     [tg, app, err] = RK4Solve(testeq,t0,tf,y0, 100)
     print(err)
     errVSh(testeq, 0 ,1 ,y0)
     t = np.linspace(0, 1 ,1000)
     plt.figure(2)
     plt.plot(tg, app, 'k')    
     plt.plot(t, solution(y0,t), 'r--' )
     plt.show()

     t,y = adaptiveRK34(testeqnbr, 0, 1, 1, 10**(-6))  
     tbig = np.linspace(0,1,1000)  


     plt.plot(t,y)
     plt.plot(tbig, solution(np.array([1]), tbig))
     plt.show()

def VanDerPolSolver():
    mu = 100
    tol = 1e-7
    t0 = 0 
    tf = 300
    u_f0 = np.array([2, 0])
    u2_f0 = np.array([3 , 1]) 
    vanDerPol = lambda t, u: np.array([u[1] , mu*(1-u[0]**2)*u[1] -u[0] ])
    [t, y , _] = adaptiveRK34(vanDerPol, t0, tf, u_f0, tol)
    [t2, y2, _] = adaptiveRK34(vanDerPol, t0, 3*tf, u2_f0, tol)

    title = "Solution to initial condition over time t with u_f0 = [ "
    add = ",".join(str(x) for x in u_f0)
    add2 = ",".join(str(x) for x in u2_f0)

    figure, axis = plt.subplots(2,2)
    axis[0, 0].plot(t, y[:,1])
    axis[0, 0].set_title(title + add + " ]")

    axis[0, 1].plot(y[:,0], y[:,1], 'm')
    axis[0, 1].set_title("Phase portrait when u_f0 = [ " + add + " ]")

    axis[1, 0].plot(t2, y2[:,1], 'r')
    axis[1, 0].set_title(title + add2 + " ]")

    axis[1, 1].plot(y2[:,0], y2[:,1], 'm')
    axis[1, 1].set_title("Phase portrait when u_f0 = [ " + add2 + " ]")
    plt.show()
    #Task 3.2
    
def VanDerPol32():
    muus = np.array([10, 15, 22, 33, 47, 68, 100, 150, 220, 330, 470, 680, 1000]) #1000 läggs till så blir det 13 fönster
    tol = 1e-7
    t0 = 0 
    tf = 50
    u_f0 = np.array([2, 0])
   
    Ns = []
    Ns2 = []
    for i in range (0, 13,1):
        vanDerPol = lambda t, u: np.array([u[1] , muus[i]*(1-u[0]**2)*u[1] -u[0] ])
        _, _, nbr = adaptiveRK34(vanDerPol, t0, tf, u_f0, tol)
        Ns.append(nbr)
        sol = integrate.solve_ivp(vanDerPol, [t0,tf], u_f0, method='BDF' )
        implicit = len(sol.t) - 1
        Ns2.append(implicit)
    print(Ns)
    print(Ns2)

    plt.figure(1)
    plt.plot(muus,Ns, 'm')
    plt.plot(muus, Ns2, 'b')
    plt.title("Stiffness: Number of Steps Against Müh")
    plt.show()

    #Task 3.3 only
    
    muus2 = np.array([10, 15, 22, 33, 47, 68, 100, 150, 220, 330, 470, 680, 1000, 4000, 10000]) 
    print(muus2)    
    vanDerPol4000 = lambda t, u: np.array([u[1] , 4000*(1-u[0]**2)*u[1] -u[0] ])
    sol4000 = integrate.solve_ivp(vanDerPol4000, [t0,tf], u_f0, method='BDF' )
    implicit = len(sol4000.t) - 1
    Ns2.append(implicit)
    vanDerPol10000 = lambda t, u: np.array([u[1] , 10000*(1-u[0]**2)*u[1] -u[0] ])
    sol10000 = integrate.solve_ivp(vanDerPol10000, [t0,tf], u_f0, method='BDF' )
    implicit = len(sol10000.t) - 1
    Ns2.append(implicit)
    
    plt.figure(2)
    plt.semilogy(muus2, Ns2)
    plt.title("Only implicit BDF Method")
    plt.show()

if __name__ == '__main__':
    # task1Solver()
    # lotkaVolterraSolver()
    # VanDerPolSolver()
    VanDerPol32()
Editor is loading...