コード例 #1
0
def implicitsolve(mx, mt, L, T, c, source, ix, iv, lbc, rbc, lbctype, rbctype):
    """
    Solve a wave equation using an implicit scheme. Unconditionally stable.
    """
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, c)

    # make sure these functions are vectorized
    ix, iv, lbc, rbc, source = numpify_many((ix, 'x'), (iv, 'x'), (lbc, 't'),
                                            (rbc, 't'), (source, 'x t'))

    # construct matrices for implicit scheme
    A_IW = tridiag(mx + 1, -0.5 * lmbda**2, 1 + lmbda**2, -0.5 * lmbda**2)
    B_IW = tridiag(mx + 1, 0.5 * lmbda**2, -1 - lmbda**2, 0.5 * lmbda**2)

    # corrections for Neumann conditions
    A_IW[0, 1] *= 2
    B_IW[0, 1] *= 2
    A_IW[mx, mx - 1] *= 2
    B_IW[mx, mx - 1] *= 2

    # range of rows of A_EW to use
    a = 1 if lbctype == 'Dirichlet' else 0
    b = mx if rbctype == 'Dirichlet' else mx + 1

    # initial condition vectors
    U = ix(xs).copy()
    V = iv(xs).copy()

    # set first two time steps
    u_jm1 = U
    u_j = spsolve(A_IW, U - deltat * B_IW.dot(V))

    # initialise u at next time step
    u_jp1 = np.zeros(xs.size)
    v = np.zeros(xs.size)

    for j in ts[1:-1]:
        v[a:b] = B_IW[a:b, a:b].dot(u_jm1[a:b]) + 2 * u_j[a:b]

        addboundaries(v, lbctype, rbctype,
                      0.5 * lmbda**2 * (lbc(j) + lbc(j + deltat)),
                      0.5 * lmbda**2 * (rbc(j) + rbc(j + deltat)),
                      -lmbda**2 * deltax * (lbc(j) + lbc(j + deltat)),
                      lmbda**2 * deltax * (rbc(j) + rbc(j + deltat)))

        u_jp1[a:b] = spsolve(A_IW[a:b, a:b], v[a:b])

        if lbctype == 'Dirichlet':
            u_jp1[0] = lbc(j + deltat)
        if rbctype == 'Dirichlet':
            u_jp1[mx] = rbc(j + deltat)

        # add source to inner terms
        u_jp1[1:-1] += deltat * source(xs[1:-1], j)

        # update u_jm1 and u_j
        u_jm1[:], u_j[:] = u_j[:], u_jp1[:]

    return xs, u_j, lmbda
コード例 #2
0
ファイル: parabolicsolvers.py プロジェクト: jc4196/pdes
def cranknicholson(mx, mt, L, T, kappa, source, ic, lbc, rbc, lbctype,
                   rbctype):
    """Crank-Nicholson finite-difference scheme (implicit) for solving 
    parabolic PDE problems. Unconditionally stable"""

    # initialise
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, kappa)

    u_j = ic(xs)

    # if boundary conditions don't match initial conditions
    if lbctype == 'Dirichlet':
        u_j[0] = lbc(0)
    if rbctype == 'Dirichlet':
        u_j[mx] = rbc(0)

    u_jp1 = np.zeros(xs.size)
    v = np.zeros(xs.size)

    # Construct Crank-Nicholson matrices
    A_CN = tridiag(mx + 1, -0.5 * lmbda, 1 + lmbda, -0.5 * lmbda)
    B_CN = tridiag(mx + 1, 0.5 * lmbda, 1 - lmbda, 0.5 * lmbda)
    # modify first and last row for Neumann conditions
    A_CN[0, 1] *= 2
    A_CN[mx, mx - 1] *= 2
    B_CN[0, 1] *= 2
    B_CN[mx, mx - 1] *= 2

    # range of rows of matrices to use
    a, b = matrixrowrange(mx, lbctype, rbctype)

    # Solve the PDE at each time step
    for t in ts[:-1]:
        v[a:b] = B_CN[a:b, a:b].dot(u_j[a:b])

        addboundaries(v, lbctype, rbctype,
                      0.5 * lmbda * (lbc(t) + lbc(t + deltat)),
                      0.5 * lmbda * (rbc(t) + rbc(t + deltat)),
                      -lmbda * deltax * (lbc(t) + lbc(t + deltat)),
                      lmbda * deltax * (rbc(t) + rbc(t + deltat)))

        u_jp1[a:b] = spsolve(A_CN[a:b, a:b], v[a:b])

        # fix Dirichlet boundary conditions
        if lbctype == 'Dirichlet':
            u_jp1[0] = lbc(t)
        if rbctype == 'Dirichlet':
            u_jp1[mx] = rbc(t)

        # add source to inner terms
        u_jp1[1:-1] += 0.5 * deltat * (source(xs[1:-1], t) +
                                       source(xs[1:-1], t + deltat))

        u_j[:] = u_jp1[:]

    return xs, u_j
コード例 #3
0
def cranknicholson(mx, mt, L, T, kappa, source, ic, lbc, rbc, lbctype,
                   rbctype):
    """Crank-Nicholson finite-difference scheme (implicit) for solving 
    parabolic PDE problems. Unconditionally stable"""

    # initialise   parameters
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, kappa)

    # make sure these functions are vectorized
    ic, lbc, rbc, source = numpify_many((ic, 'x'), (lbc, 't'), (rbc, 't'),
                                        (source, 'x t'))

    # Construct Crank-Nicholson matrices
    A_CN = tridiag(mx + 1, -0.5 * lmbda, 1 + lmbda, -0.5 * lmbda)
    B_CN = tridiag(mx + 1, 0.5 * lmbda, 1 - lmbda, 0.5 * lmbda)
    # modify first and last row for Neumann conditions
    A_CN[0, 1] *= 2
    A_CN[mx, mx - 1] *= 2
    B_CN[0, 1] *= 2
    B_CN[mx, mx - 1] *= 2

    # restrict range of A_CN and B_CN in case of Dirichlet conditions
    a = 1 if lbctype == 'Dirichlet' else 0
    b = mx if rbctype == 'Dirichlet' else mx + 1

    # initialise first time steps
    u_j = ic(xs).copy()
    u_jp1 = np.zeros(xs.size)
    v = np.zeros(xs.size)

    # Solve the PDE at each time step
    for j in ts[:-1]:
        v[a:b] = B_CN[a:b, a:b].dot(u_j[a:b])

        addboundaries(v, lbctype, rbctype,
                      0.5 * lmbda * (lbc(j) + lbc(j + deltat)),
                      0.5 * lmbda * (rbc(j) + rbc(j + deltat)),
                      -lmbda * deltax * (lbc(j) + lbc(j + deltat)),
                      lmbda * deltax * (rbc(j) + rbc(j + deltat)))

        u_jp1[a:b] = spsolve(A_CN[a:b, a:b], v[a:b])

        # fix Dirichlet boundary conditions
        if lbctype == 'Dirichlet':
            u_jp1[0] = lbc(j)
        if rbctype == 'Dirichlet':
            u_jp1[mx] = rbc(j)

        # add source to inner terms
        u_jp1[1:-1] += 0.5 * deltat * (source(xs[1:-1], j) +
                                       source(xs[1:-1], j + deltat))

        u_j[:] = u_jp1[:]

    return xs, u_j, lmbda
コード例 #4
0
def explicitsolve(mx, mt, L, T, c, source, ix, iv, lbc, rbc, lbctype, rbctype):
    """
    Solve a wave equation using an explicit scheme. Conditionally
    stable for lambda <= 1. lambda = 1 is the 'magic step'.
    """
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, c)

    # make sure these functions are vectorized
    ix, iv, lbc, rbc, source = numpify_many((ix, 'x'), (iv, 'x'), (lbc, 't'),
                                            (rbc, 't'), (source, 'x t'))

    # Construct explicit wave matrix
    A_EW = tridiag(mx + 1, lmbda**2, 2 - 2 * lmbda**2, lmbda**2)

    # Changes for Neumann boundary conditions
    A_EW[0, 1] *= 2
    A_EW[mx, mx - 1] *= 2

    # range of rows of A_EW to use
    a = 1 if lbctype == 'Dirichlet' else 0
    b = mx if rbctype == 'Dirichlet' else mx + 1

    # initial condition vectors
    U = ix(xs).copy()
    V = iv(xs).copy()

    # set first two time steps
    u_jm1 = U
    u_j = 0.5 * A_EW.dot(U) + deltat * V

    # initialise u at next time step
    u_jp1 = np.zeros(xs.size)

    for j in ts[1:-1]:
        u_jp1[a:b] = A_EW[a:b, a:b].dot(u_j[a:b]) - u_jm1[a:b]

        addboundaries(u_jp1, lbctype, rbctype, lmbda**2 * lbc(j - deltat),
                      lmbda**2 * rbc(j - deltat),
                      -2 * lmbda**2 * deltax * lbc(j - deltat),
                      2 * lmbda**2 * deltax * rbc(j - deltat))

        # fix Dirichlet boundary conditions
        if lbctype == 'Dirichlet':
            u_jp1[0] = lbc(j + deltat)
        if rbctype == 'Dirichlet':
            u_jp1[mx] = rbc(j + deltat)

        # add source to inner terms
        u_jp1[1:-1] += deltat * source(xs[1:-1], j)

        # update u_jm1 and u_j
        u_jm1[:], u_j[:] = u_j[:], u_jp1[:]

    return xs, u_j, lmbda
コード例 #5
0
def backwardeuler(mx, mt, L, T, kappa, source, ic, lbc, rbc, lbctype, rbctype):
    """Backward Euler finite-difference scheme (implicit) for solving 
    parabolic PDE problems. Unconditionally stable"""

    # initialise   parameters
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, kappa)

    # make sure these functions are vectorized
    ic, lbc, rbc, source = numpify_many((ic, 'x'), (lbc, 't'), (rbc, 't'),
                                        (source, 'x t'))

    # Construct backward Euler matrix
    B_FE = tridiag(mx + 1, -lmbda, 1 + 2 * lmbda, -lmbda)

    # modify first and last row for Neumann conditions
    B_FE[0, 1] *= 2
    B_FE[mx, mx - 1] *= 2

    # restrict range of B_FE to use in case of Dirichlet conditions
    a = 1 if lbctype == 'Dirichlet' else 0
    b = mx if rbctype == 'Dirichlet' else mx + 1

    # initialise first time steps
    u_j = ic(xs).copy()
    u_jp1 = np.zeros(xs.size)

    # Solve the PDE at each time step
    for j in ts[:-1]:
        # modifications to the boundaries
        addboundaries(
            u_j,
            lbctype,
            rbctype,
            lmbda * lbc(j + deltat),  # Dirichlet u[1]
            lmbda * rbc(j + deltat),  # Dirichlet u[-2]
            -2 * lmbda * deltax * lbc(j + deltat),  # Neumann u[0]
            2 * lmbda * deltax * rbc(j + deltat))  # Neumann u[-1]

        u_jp1[a:b] = spsolve(B_FE[a:b, a:b], u_j[a:b])

        # fix Dirichlet boundary conditions
        if lbctype == 'Dirichlet':
            u_jp1[0] = lbc(j + deltat)
        if rbctype == 'Dirichlet':
            u_jp1[mx] = rbc(j + deltat)

        # add source to inner terms
        u_jp1[1:-1] += deltat * source(xs[1:-1], j + deltat)

        u_j[:] = u_jp1[:]

    return xs, u_j, lmbda
コード例 #6
0
ファイル: parabolicsolvers.py プロジェクト: jc4196/pdes
def backwardeuler(mx, mt, L, T, kappa, source, ic, lbc, rbc, lbctype, rbctype):
    """Backward Euler finite-difference scheme (implicit) for solving 
    parabolic PDE problems. Unconditionally stable"""

    # initialise
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, kappa)

    ic, lbc, rbc, source = numpify_many((ic, 'x'), (lbc, 'x'), (rbc, 'x'),
                                        (source, 'x t'))

    u_j = ic(xs)
    print(type(u_j))
    plot_solution(xs, u_j)
    # if boundary conditions don't match initial conditions
    if lbctype == 'Dirichlet':
        u_j[0] = lbc(0)
    if rbctype == 'Dirichlet':
        u_j[mx] = rbc(0)

    u_jp1 = np.zeros(xs.size)

    # Construct forward Euler matrix
    B_FE = tridiag(mx + 1, -lmbda, 1 + 2 * lmbda, -lmbda)

    # modify first and last row for Neumann conditions
    B_FE[0, 1] *= 2
    B_FE[mx, mx - 1] *= 2

    # range of rows of B_FE to use
    a, b = matrixrowrange(mx, lbctype, rbctype)
    print(a, b)
    # Solve the PDE at each time step
    for t in ts[:-1]:
        addboundaries(u_j, lbctype, rbctype, lmbda * lbc(t + deltat),
                      lmbda * rbc(t + deltat),
                      -2 * lmbda * deltax * lbc(t + deltat),
                      2 * lmbda * deltax * rbc(t + deltat))

        u_jp1[a:b] = spsolve(B_FE[a:b, a:b], u_j[a:b])

        # fix Dirichlet boundary conditions
        if lbctype == 'Dirichlet':
            u_jp1[0] = lbc(t + deltat)
        if rbctype == 'Dirichlet':
            u_jp1[mx] = rbc(t + deltat)

        # add source to inner terms
        u_jp1[1:-1] += deltat * source(xs[1:-1], t + deltat)

        u_j[:] = u_jp1[:]

    return xs, u_j
コード例 #7
0
def tsunami_solve(mx, mt, L, T, h0, h, wave):
    """Variable wavespeed problem assumes periodic boundary on the left and 
    an open boundary on the right"""
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, np.sqrt(h0))

    h, wave = numpify_many((h, 'x'), (wave, 'x'))
    delta = deltat / deltax

    # construct explicit wave matrix for variable wave speed problem
    # with open boundary conditions initially
    lower = [delta**2 * h(i - 0.5 * deltax) for i in xs[1:-1]] + [2 * lmbda**2]
    main = [2*(1 + lmbda - lmbda**2)] + \
            [2 - delta**2*(h(i + 0.5*deltax) + h(i - 0.5*deltax)) for i in xs[1:-1]] + \
             [2*(1 + lmbda - lmbda**2)]
    upper = [2 * lmbda**2] + [delta**2 * h(i + 0.5 * deltax) for i in xs[1:-1]]

    A_EW = tridiag(mx + 1, lower, main, upper)

    # initial condition vectors
    u = [np.zeros(xs.size) for i in range(mt + 1)]

    U = wave(xs).copy()

    # set first two time steps
    u[0] = U
    u[1] = 0.5 * A_EW.dot(U)

    # keep track of the first time the right side becomes non-zero
    zero_right = True

    for j in range(1, mt):
        u[j + 1] = A_EW.dot(u[j]) - u[j - 1]

        # correction for open boundary condition
        u[j + 1][mx] /= (1 + 2 * lmbda)

        # switch from open to periodic boundary
        if zero_right and u[j + 1][mx] > 1e-5:
            zero_right = False

        # correction for open boundary conditon on the left before
        # it becomes a periodic condition
        if zero_right:
            u[j + 1][0] /= (1 + 2 * lmbda)
        else:
            # periodic condition
            u[j + 1][0] = u[j + 1][mx]

    return xs, u
コード例 #8
0
ファイル: parabolicsolvers.py プロジェクト: jc4196/pdes
def forwardeuler(mx, mt, L, T, kappa, source, ic, lbc, rbc, lbctype, rbctype):
    """Forward euler finite-difference scheme (explicit) for solving
    parabolic PDE problems. Values of lambda > 1/2 will cause the scheme
    to become unstable"""

    # initialise
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, kappa)

    u_j = ic(xs)

    # if boundary conditions don't match initial conditions
    if lbctype == 'Dirichlet':
        u_j[0] = lbc(0)
    if rbctype == 'Dirichlet':
        u_j[mx] = rbc(0)

    u_jp1 = np.zeros(xs.size)

    # Construct forward Euler matrix
    A_FE = tridiag(mx + 1, lmbda, 1 - 2 * lmbda, lmbda)

    # modify first and last row for Neumann conditions
    A_FE[0, 1] *= 2
    A_FE[mx, mx - 1] *= 2

    # range of rows of A_FE to use
    a, b = matrixrowrange(mx, lbctype, rbctype)

    # Solve the PDE at each time step
    for t in ts[:-1]:
        u_jp1[a:b] = A_FE[a:b, a:b].dot(u_j[a:b])

        addboundaries(u_jp1, lbctype, rbctype, lmbda * lbc(t), lmbda * rbc(t),
                      -2 * lmbda * deltax * lbc(t),
                      2 * lmbda * deltax * rbc(t))

        # fix Dirichlet boundary conditions
        if lbctype == 'Dirichlet':
            u_jp1[0] = lbc(t + deltat)
        if rbctype == 'Dirichlet':
            u_jp1[mx] = rbc(t + deltat)

        # add source to inner terms
        u_jp1[1:-1] += deltat * source(xs[1:-1], t)

        u_j[:] = u_jp1[:]

    return xs, u_j
コード例 #9
0
def forwardeuler(mx, mt, L, T, kappa, source, ic, lbc, rbc, lbctype, rbctype):
    """Forward euler finite-difference scheme (explicit) for solving
    parabolic PDE problems. Values of lambda > 1/2 will cause the scheme
    to become unstable"""

    # initialise
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, kappa)

    # make sure these functions are vectorized
    ic, lbc, rbc, source = numpify_many((ic, 'x'), (lbc, 't'), (rbc, 't'),
                                        (source, 'x t'))

    # Construct forward Euler matrix
    A_FE = tridiag(mx + 1, lmbda, 1 - 2 * lmbda, lmbda)

    # modify first and last row for Neumann conditions
    A_FE[0, 1] *= 2
    A_FE[mx, mx - 1] *= 2

    # initialise first time steps
    u_j = ic(xs).copy()
    u_jp1 = np.zeros(xs.size)

    # range of rows of A_FE to use
    a = 1 if lbctype == 'Dirichlet' else 0
    b = mx if rbctype == 'Dirichlet' else mx + 1

    # Solve the PDE at each time step
    for j in ts[:-1]:
        u_jp1[a:b] = A_FE[a:b, a:b].dot(u_j[a:b])

        addboundaries(u_jp1, lbctype, rbctype, lmbda * lbc(j), lmbda * rbc(j),
                      -2 * lmbda * deltax * lbc(j),
                      2 * lmbda * deltax * rbc(j))

        # fix Dirichlet boundary conditions
        if lbctype == 'Dirichlet':
            u_jp1[0] = lbc(j + deltat)
        if rbctype == 'Dirichlet':
            u_jp1[mx] = rbc(j + deltat)

        # add source to inner terms
        u_jp1[1:-1] += deltat * source(xs[1:-1], j)

        u_j[:] = u_jp1[:]

    return xs, u_j, lmbda
コード例 #10
0
def backwardeuler2(mx, mt, L, T, kappa, source, ic, lbc, rbc, lbc_ab, rbc_ab):
    """
    Second implementation of backward Euler that takes mixed boundary
    conditions
    """

    # initialise   parameters
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, kappa)

    # make sure these functions are vectorized
    ic, lbc, rbc, source = numpify_many((ic, 'x'), (lbc, 't'), (rbc, 't'),
                                        (source, 'x t'))

    # Parameters needed to construct the matrix
    alpha1, beta1 = lbc_ab
    alpha2, beta2 = rbc_ab

    # Construct the backward Euler matrix, first and last row are
    # boundary condition equations
    lower = (mx - 1) * [-lmbda] + [-beta2]
    main = [alpha1*deltax - beta1] + (mx-1)*[1+2*lmbda] + \
                [beta2 + alpha2*deltax]
    upper = [beta1] + (mx - 1) * [-lmbda]
    A_BE = tridiag(mx + 1, lower, main, upper)

    # initialise the first time steps
    u_j = ic(xs).copy()
    u_jp1 = np.zeros(xs.size)

    # Solve the PDE: loop over all time points
    for j in ts[:-1]:
        # Add boundary conditions to vector u_j
        u_j[0] = deltax * lbc(j * deltat)
        u_j[mx] = deltax * rbc(j * deltat)

        # Backward euler timestep
        u_jp1 = spsolve(A_BE, u_j)

        # add source function
        u_jp1[1:mx] += deltat * source(xs[1:-1], j * deltat)

        # Update u_j
        u_j[:] = u_jp1[:]

    return xs, u_j, lmbda
コード例 #11
0
def implicitsolve(mx, mt, L, T,
                  c, source,
                  ix, iv,
                  lbc, rbc, lbctype, rbctype):
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, c)
  
    # Get matrices and vector for the particular scheme
    A_IW = tridiag(mx+1, -0.5*lmbda**2, 1+lmbda**2, -0.5*lmbda**2)
    B_IW = tridiag(mx+1, 0.5*lmbda**2, -1-lmbda**2, 0.5*lmbda**2)
    
    # corrections for Neumann conditions
    A_IW[0,1] *= 2; B_IW[0,1] *= 2; A_IW[mx,mx-1] *= 2; B_IW[mx,mx-1] *= 2


    a, b = matrixrowrange(mx, lbctype, rbctype)
    
    # initial condition vectors
    U = ix(xs)
    V = iv(xs)
    
    # set first two time steps
    u_jm1 = U 
    
    u_j = np.zeros(xs.size)
    w = np.zeros(xs.size)
    
    w = U - deltat*B_IW.dot(V)
    u_j = spsolve(A_IW, w)
    
    # boundary conditions (may not match initial conditions)   
    if lbctype == 'Dirichlet':
        u_j[0] = lbc(0)
        
    if rbctype == 'Dirichlet':
        u_j[mx] = rbc(0)     
    

    # initialise u at next time step
    u_jp1 = np.zeros(xs.size)
    v = np.zeros(xs.size)        
    

    for t in ts[1:-1]:
        v = B_IW.dot(u_jm1) + 2*u_j
 
        addboundaries(v, lbctype, rbctype,
                      0.5*lmbda**2*(lbc(t) + lbc(t + deltat)),
                      0.5*lmbda**2*(rbc(t) + rbc(t + deltat)),
                       -lmbda**2*deltax*(lbc(t) + lbc(t + deltat)),
                      lmbda**2*deltax*(rbc(t) + rbc(t + deltat)))

        u_jp1 = spsolve(A_IW, v)
        
        if lbctype == 'Dirichlet':
            u_jp1[0] = lbc(t + deltat)
        if rbctype == 'Dirichlet':
            u_jp1[mx] = rbc(t + deltat)
        
        # apply open boundary conditions
        if lbctype == 'Open':
            u_jp1[0] = (1-lmbda)*u_j[0] + lmbda*u_j[1]
        if rbctype == 'Open':
            u_jp1[mx] = lmbda*u_j[mx-1] + (1-lmbda)*u_j[mx]
            
        # add source to inner terms
        u_jp1[1:-1] += deltat*source(xs[1:-1], t)
        
        # update u_jm1 and u_j
        u_jm1[:], u_j[:] = u_j[:], u_jp1[:]
    
    return xs, u_j
コード例 #12
0
def explicitsolve(mx, mt, L, T,
                  c, source,
                  ix, iv,
                  lbc, rbc, lbctype, rbctype):
    """Solve a wave equation problem with the given spacing"""
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, c)
    print("lambda = %f" % lmbda)
    
    # Construct explicit wave matrix
    A_EW = tridiag(mx+1, lmbda**2, 2-2*lmbda**2, lmbda**2)    
    
    ##### Put changes to the matrix into a separate function ######
    if lbctype == 'Neumann':
        A_EW[0,1] *= 2
    elif lbctype == 'Open' or lbctype == 'Periodic':
        A_EW[0,0] = 2*(1 + lmbda - lmbda**2); A_EW[0,1] = 2*lmbda**2
    
    if rbctype == 'Neumann':
        A_EW[mx,mx-1] *= 2
    elif rbctype == 'Open' or rbctype == 'Periodic':
        A_EW[mx,mx-1] = 2*lmbda**2; A_EW[mx,mx] = 2*(1 + lmbda - lmbda**2)
    
    # This was an attempt to include the open boundary condition in the matrix
    #if lbctype == 'Open':
    #    A_EW[0,0] = 1 + lmbda; A_EW[0,1] = -lmbda
    #if rbctype =='Open':
    #    A_EW[mx,mx-1] = 1 - lmbda; A_EW[mx,mx] = lmbda
    
    ### and perhaps include this ###
    a, b = matrixrowrange(mx, lbctype, rbctype)

    # initial condition vectors
    U = ix(xs)
    V = iv(xs)
    
    # set first two time steps
    u_jm1 = U 

    u_j = np.zeros(xs.size)
    u_j = 0.5*A_EW.dot(U) + deltat*V

    # boundary conditions (may not match initial conditions)

    ### separate function for adding Dirichlet conditions ###
    if lbctype == 'Dirichlet':
        u_j[0] = lbc(0)
        
    if rbctype == 'Dirichlet':
        u_j[mx] = rbc(0)     
 
    # initialise u at next time step
    u_jp1 = np.zeros(xs.size)        
   
    zero_left, zero_right = True, True
    
    for t in ts[1:-1]:
        u_jp1 = A_EW.dot(u_j) - u_jm1

        addboundaries(u_jp1, lbctype, rbctype,
                      lmbda**2*lbc(t - deltat),
                      lmbda**2*rbc(t - deltat),
                      -2*lmbda**2*deltax*lbc(t - deltat),
                      2*lmbda**2*deltax*rbc(t - deltat))

        # apply open boundary conditions
        if lbctype == 'Open' or (lbctype == 'Periodic' and zero_right):
            #u_jp1[0] = (1-lmbda)*u_j[0] + lmbda*u_j[1]
            u_jp1[0] /= (1+2*lmbda)
        if rbctype == 'Open' or (rbctype == 'Periodic' and zero_left):
            #u_jp1[mx] = lmbda*u_j[mx-1] + (1-lmbda)*u_j[mx]
            u_jp1[mx] /= (1+2*lmbda)
        
        # fix Dirichlet boundary conditions
        if lbctype == 'Dirichlet':
            u_jp1[0] = lbc(t + deltat)
        if rbctype == 'Dirichlet':
            u_jp1[mx] = rbc(t + deltat)
        
        if zero_left:
            if u_jp1[0] > 1e-6:
                zero_left = False
        
        if zero_right:            
            if u_jp1[mx] > 1e-6:
                zero_right = False
        
        if lbctype == 'Periodic':
            if zero_right == False:
                u_jp1[0] = u_jp1[mx]
                
        if rbctype == 'Periodic':
            if zero_left == False:
                u_jp1[mx] = u_jp1[0]
                
        # add source to inner terms
        #u_jp1[1:-1] += deltat*source(xs[-1:1], t)
        
        # update u_jm1 and u_j
        u_jm1[:], u_j[:] = u_j[:], u_jp1[:]
    
    return xs, u_j
コード例 #13
0
        c        wave speed
        ix       initial displacement function
        iv       initial velocity function
        lbc      left boundary condition function
        rbc      right boundary condition function
        lbctype  left boundary type eg. 'Dirichlet'
        rbctype  right boundary type
        
        Returns
        xs       the points at which the solution is found
        uT       the solution at time T
    """
    xs, ts, deltax, deltat, lmbda = initialise(mx, mt, L, T, c)
    print("lambda = %f" % lmbda)
    # Construct explicit wave matrix
    A_EW = tridiag(mx+1, lmbda**2, 2-2*lmbda**2, lmbda**2)
    
    ##### Put changes to the matrix into a separate function ######
    A_EW[0,1] *= 2; A_EW[mx,mx-1] *= 2
    
    # This was an attempt to include the open boundary condition in the matrix
    #if lbctype == 'Open':
    #    A_EW[0,0] = 1 + lmbda; A_EW[0,1] = -lmbda
    #if rbctype =='Open':
    #    A_EW[mx,mx-1] = 1 - lmbda; A_EW[mx,mx] = lmbda
    
    ### and perhaps include this ###
    a, b = matrixrowrange(mx, lbctype, rbctype)

    # initial condition vectors
    U = ix(xs)