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
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
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
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
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
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
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
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
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
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
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
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
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)