Untitled

 avatar
unknown
python
4 years ago
6.1 kB
6
Indexable
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from scipy.linalg import expm
from scipy import integrate
from scipy.sparse.linalg import spsolve
import scipy.sparse.linalg
from scipy.sparse import linalg as sla
import time
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.spsolve.html

def twopBVP(fvec, alpha, beta, L, N):
    dx = L/(N+1)
    fvec[0] -= alpha/dx**2 
    fvec[-1] -= beta/dx**2 #(f - b) from lecture notes
    Tdx = scipy.sparse.csr_matrix((1/(dx**2))*(np.diag(-2*np.ones(N)) + np.diag(np.ones(N-1),1) +  np.diag(np.ones(N-1),-1) ))
    y = spsolve(Tdx, fvec)
    return np.array([alpha, *y, beta])

def task1p1():
    L = 10
    alpha = 1
    beta = 2
    N = 100
    x = np.linspace(0, L, N+2)
    inx = x[1:-1]
    f = lambda x: np.exp(-x)
    f = np.vectorize(f)
    g = np.exp(-x)
    
    ys = twopBVP(f(inx), g[0], g[-1], L, N )
    
    Nbr = [2**4, 2**6, 2**8, 2**10, 2**12]
    err = []
    h = []
    for i in Nbr:
        delx = L/(i+1)
        ingrid = np.arange(0, L , delx)
        fvec = f(ingrid)
        alpha = f(ingrid[0])
        beta = f(L)
        fvec = np.delete(fvec, 0)
        y = twopBVP(fvec, alpha, beta, L, i)
        ingrid = np.append(ingrid, L)
        err.append(np.linalg.norm(y - f(ingrid) )*np.sqrt(delx))
        h.append(1/i)
    
    plt.figure(1)
    plt.loglog(h, err, 'm', label='error')
    plt.loglog(h, np.multiply(h,h), label='h^2')
    plt.title('Error for Custom d^2/dx^2y = f(x,y)')
    plt.legend()
    plt.grid()
    plt.show()


    plt.figure(2)
    plt.plot(x, ys, 'r--', label='approx.', )
    plt.plot(x,g, 'b--', label ='analytical sol.')
    plt.title("Approx. vs. analytical sol.")
    plt.legend()
    plt.grid()
    plt.show()


def task1p2():
    N = 999
    alpha = 0
    beta = 0
    L = 10
    x = np.linspace(0, L, N+2)
    inx = x[1:-1] 
    
    E = 1.9 * 1e11
    f = lambda x: ((-25000*x**2 + 25000*L*x)/(E*1e-3 * (3-2*np.cos(np.pi*x/L)**12)))
    f = np.vectorize(f)
    us = twopBVP(f(inx), alpha, beta, L , N)
    print('Deflection at midpoint (x,y):')
    np.printoptions(precision = 8) #does not work with correct usage of printoptions. 
    answr = [inx[500], 1e3*us[500]] #499th step will land exactly on L = 5.00 meters, yet index 500 has min value
    print(answr)

    plt.figure(1)
    plt.plot(x, us, 'r--', label = 'approx.')
    plt.ylabel('Deflection (m)')
    plt.title('Approximated Solution of The Beam Equation')
    plt.legend()
    plt.grid()
    plt.show()



def eigLaplace(L, N ):
    dx = L/(N+1)
    c = np.zeros(N)
    c[0] = -2
    c[1] = 1
    A = scipy.linalg.toeplitz(c)
    Tdx = (1/(dx**2))*(A)
    E = np.zeros((N,N))
    E[-1][-2] = 4/3
    E[-1][-1] = -1/3
    z  = Tdx + (1/dx**2)*E
    eigz, eigzvec = scipy.linalg.eig(z)
    return [eigz, eigzvec]


def Schrödinger(V, N, x, neigs):
    t0 = time.time()
    ingrid = x[1:-1]
    dx = 1/(N+1)
    Tdx = scipy.sparse.diags([1, -2, 1], [-1, 0, 1], shape=(N, N)) / dx**2
    T = Tdx - scipy.sparse.csr_matrix(V(ingrid)).multiply(scipy.sparse.identity(N))
    # help(sla.eigs)
    v, w = sla.eigsh(T, k=neigs, which ='SM')
    t1 = time.time()
    print(f'time: {t1 - t0}')
    z = np.zeros((1, neigs))
    S = np.vstack((z, w, z)) #Satisfying Dirichlet-conditions
    # print(np.size(S, 0), np.size(S, 1))

    return v, S

def task2p1():
    N = 499
    L = 1
    eigz, eigzvec = eigLaplace(L,N)
    eigenvaluef = lambda k: -1*(np.pi*(0.5 + k))**2

    plt.figure(1)
    plt.plot(eigzvec[:,np.argsort(abs(eigz))[0]], label = 'k=1')
    plt.plot(eigzvec[:,np.argsort(abs(eigz))[1]], label = 'k=2')
    plt.plot(eigzvec[:,np.argsort(abs(eigz))[2]], label = 'k=3')
    plt.legend()
    plt.title("First 3 Eigenvectors")
    plt.show()
    
    Z = np.arange(10,500,10)
    err = []
    h = []
    _, (ax1, ax2, ax3) = plt.subplots(3, 1, sharex=True)
    for i in Z:
        
        for k in range(1,4):
            y = eigLaplace(L, i)
            y[0].sort()
            err.append(abs(y[0][-1] - eigenvaluef(k)))
            h.append(i)
        
    def choice(kvalue):
        switch = {
        1:  ax1.loglog(h, err, 'm', label = 'k = {k}'),
        2:  ax2.loglog(h, err, 'm', label = 'k = {k}'),
        3:  ax3.loglog(h, err, 'm', label = 'k = {k}')
        }
        choice(k)
    plt.show()
        
       
    

def task2p2(vname, V):
    N = 1000
    neigs = 7
    V = np.vectorize(V)
    xgrid = np.linspace(0,1, N+2)
       
    d, S = Schrödinger(V, N, xgrid, neigs)
    # print(f'First {neigs} energy levels: {-1*d}')
    # print(f'First {neigs} wave functions: ')
    # print(S)
    
    pnorm = 1/N**2
    _, (ax1, ax2, ax3) = plt.subplots(3, 1, sharex=True)        
    ax1.plot(xgrid, V(xgrid), 'k', label = vname)
    ax1.legend(loc = 'upper right')
    for i in range(neigs):
        E = -d[i]
        psi = S[:,i]
        
        psi /= pnorm
        probDens = np.real(np.conj(psi)*psi) 

        ax2.plot(xgrid, psi + E)
        ax3.plot(xgrid, probDens + E)
    psiname = f'$\hat\psi$'
    psisquare = f'$|\hat\psi|^2$'
    ax1.set(title = f'Smallest {neigs} $\hat\psi$ and $|\hat\psi|^2 $ \n in ascending energy magnitude, \n with N = {N} and norm  = ' + r'$N^{-2}$.')
    ax1.set(ylabel = '$V$')
    ax2.set(ylabel = psiname)
    ax3.set(ylabel = psisquare)
    ax3.set(xlabel ='$x$')

    plt.show()
    
    print("Energy Eigenvalues, V(x) = " + vname)
    E = np.sort(-d)
    for i,j in enumerate(E):
        print("{}: {:.2f}".format(i+1,j))
    

    
if __name__ == '__main__':
    # task1p1()
    # task1p2()   
    task2p1()
    # task2p2("$800\sin(\pi x)^2$", V = lambda x: 800*np.multiply(np.sin(np.pi*x), np.sin(np.pi*x)) )
    # task2p2("$  0.5 (x - 0.5)^2  $", V = lambda x: 0.5*(x - 0.5)**2) 
    # task2p2("0", V = lambda x: 0)
    # task2p2("700*(0.5- abs(x - 0.5))", V = lambda x: 700*(0.5- abs(x-0.5)))
Editor is loading...