def solve_at_T(self, T, mx, mt, plot=False, animate=False): xs, u = tsunami_solve(mx, mt, self.L, T, self.h0, self.h, self.wave) if plot: plot_solution(xs, u[-1], uexact=self.seabed, style='r-') if animate: animate_tsunami(xs, u, self.L) return u[-1]
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 solver_demonstration(): mx = 30 mt = 1000 L = 1 T = 0.5 def uI(x): return np.sin(np.pi * x / L) xs, uT, lmbda = backwardeuler(mx, mt, L, T, 1, 0, uI, 0, 0, 'Dirichlet', 'Dirichlet') plot_solution(xs, uT)
def solve_at_T(self, T, mx, mt, scheme, u_exact=None, plot=True, norm='L2', title=''): """ Solve the diffusion equation at time T with grid spacing mx x mt. Parameters T time to stop the integration mx number of grid points in space mt number of grid points in time scheme the solver to use e.g. forwardeuler, cranknicholson u_exact the exact solution (sympy expression) plot plot the results if True title title for the plot Returns uT the solution at time T err the absolute error (if u_exact is given) """ # solve the PDE by the given scheme xs, uT, lmbda = (SCHEMES[scheme])(mx, mt, self.L, T, self.kappa, self.source, self.ic, self.lbc.rhs, self.rbc.rhs, self.lbc.type, self.rbc.type) if u_exact: # substitute in the values of kappa, L and T uTsym = u_exact.subs({kappa: self.kappa, L: self.L, t: T}) # calculate absolute error error = get_error(xs, uT, uTsym, norm=norm) if plot: plot_solution(xs, uT, uTsym, title=title, uexacttitle=r'${}$'.format(sp.latex(uTsym))) else: error = None if plot: plot_solution(xs, uT, title=title) return uT, error, lmbda
def solve_at_T(self, T, mx, mt, scheme, plot=True, u_exact=None, title=''): xs, uT = scheme(mx, mt, self.L, T, self.c, self.source, self.ix, self.iv, self.lbc.apply_rhs, self.rbc.apply_rhs, self.lbc.get_type(), self.rbc.get_type()) if u_exact: uTsym = u_exact.subs({c: self.c, L: self.L, t: T}) #u = sp.lambdify(x, uTsym) u = numpify((uTsym, 'x')) error = np.linalg.norm(u(xs) - uT) if plot: plot_solution(xs, uT, u, title=title, uexacttitle=r'${}$'.format(sp.latex(uTsym))) else: error = None if plot: plot_solution(xs, uT, title=title) return uT, error