def FFT_ibvp(t_span: list, x_span: list, Nt: int, Nx: int, ic: callable(float)): """ Fast calculate exact solution :param t_span: :param x_span: :param Nt: :param Nx: :param ic: :return: """ a = x_span[0] b = x_span[1] t0 = t_span[0] tf = t_span[1] c = 2 * b - a x_span = np.linspace(a, b, 2 * Nx + 1)[:-1] extend_x_span = np.linspace(a, c, 4 * Nx + 1)[:-1] t_span = np.linspace(t0, tf, Nt) # xsample = np.linspace(2*a-b, b, 2* Nx +1 )[:-1] icsample = np.array([ic(x) for x in x_span]) ghostsample = np.flip( np.array([ic(x) for x in np.linspace(a, b, 2 * Nx + 1)]), 0)[:-1] extend_icsample = np.hstack([icsample, ghostsample]) phasesample = np.array( [np.exp(-1j * np.pi * x / 2) for x in extend_x_span]) invphasesample = np.array( [np.exp(1j * np.pi * x / 2) for x in extend_x_span]) hsample = extend_icsample * phasesample hhat = np.fft.ifftshift(np.fft.fft(hsample)) ysample = np.array([extend_icsample]).T # phasesample = np.array([np.exp(-1j * np.pi * x/ 2) for x in x_span]) # invphasesample = np.array([np.exp(1j * np.pi * x/ 2) for x in x_span]) # hsample = icsample * phasesample # hhat = np.fft.ifftshift(np.fft.fft(hsample)) # ysample = np.array([icsample]).T print(hhat.shape) for t in t_span[1:]: evolsample = np.array([ np.exp(-pow(np.pi * (n + 0.5), 2) * t) for n in range(-2 * Nx, 2 * Nx) ]) htsmaple = np.fft.ifft(np.fft.fftshift(hhat * evolsample)) utsample = np.array([invphasesample * htsmaple]) ysample = np.hstack([ysample, utsample.T]) print(ysample.shape) print(x_span.shape, t_span.shape, ysample.shape) sol_extended = OdeResult(t=t_span, y=np.real(ysample)) sol = OdeResult(t=t_span[:], y=np.real(ysample[0:2 * Nx, :])) PlotSpaceTimePDE(sol_extended, xsample=extend_x_span, title="FFT sol on extended region for dx={:.2g}".format( 1 / 1024), xcount=50, tcount=50) PlotSpaceTimePDE(sol, xsample=x_span, title="FFT correct sol for dx={:.2g}".format(1 / 1024), xcount=25, tcount=50) Write_sol_json(sol=sol, file_name="FFT for tf={}.json".format(tf)) return sol, x_span
def LTEplot2D(grid_size=[4, 8, 16, 32, 64, 128], axis: str = 't', norm_type: str = "L1"): def d(x): return 2 + np.cos(np.pi * x) def q(x): return 0.0 def bc0(t): return 1 + np.exp(-(np.pi**2) * t / 4) def bc1(t): return -0.5 * np.pi * (1 + np.exp(-(np.pi**2) * t / 4)) def ic(x): return 2 * np.cos(0.5 * np.pi * x) def f(x, t): result = -1/ 4 * (np.pi ** 2) * np.exp(- (np.pi ** 2) * t / 4) \ * np.cos(x * np.pi/2)*(-1 + 3 *(1 + np.exp((np.pi ** 2) * t / 4))* np.cos(x * np.pi)) return result def exact_sol(x, t): return (1 + np.exp(-(np.pi**2) * t / 4)) * np.cos(np.pi * x / 2) a = 0 b = 1 t_span = [0, 0.25] methods = ["CN", "Ralston"] markdict = {4: 'x', 8: 'x', 16: 'x', 32: 'x', 64: 'x', 128: 'x', 256: "x"} markoffsetdict = dict(zip(methods, ['', ''])) for N in grid_size: dt = 1 / (8 * N**2) BC0 = BoundaryCondition(a, type="D", constraint=bc0) BC1 = BoundaryCondition(b, type="N", constraint=bc1) spgrid = SpaceGrid(a, b, N + 1) xsample = np.linspace(a, b, N + 1) # initialize the SturmLiouville system and initial-boundary value problem ST = SturmLiouville(spgrid, d, q) ibvp = IBVP(ST=ST, Nonlinear=None, IC=ic, BCs=[BC0, BC1], rhs=f) # compute the discretization and matrix involved ibvp.compute() for method in methods: json_name = "sol node={}, dt={:.2g}, for {}.json".format( N, dt, method) print(json_name) import os exists = os.path.isfile('../data/{}'.format(json_name)) if exists: # Store configuration file values sol = Read_sol_json(json_name) else: # Keep presets if (method in ["CN", "BE"]): sol = ibvp.customize_solve(t_span=t_span, type=method, max_step=dt) else: sol = ibvp.ibvp_solve(t_span=t_span, type=method, max_step=dt) Write_sol_json(sol, json_name) ysample = np.abs(sol.y - np.array([[exact_sol(x, t) for t in sol.t] for x in xsample]))[1:, 1:] tsample = sol.t[1:] sliced_xsample = xsample[1:] sol1 = OdeResult(t=tsample, y=ysample) errors = FunctionNormAlong(sol=sol1, xsample=sliced_xsample, axis=axis, type=norm_type) if axis == "t": plt.semilogy(sliced_xsample, errors, markdict[N] + markoffsetdict[method], label=json_name[4:-5]) elif axis == "x": plt.semilogy(tsample, errors, markdict[N] + markoffsetdict[method], label=json_name[4:-5]) if axis == 't': plt.xlabel("x") plt.title("x" + "-error relation in {} norm".format(norm_type)) else: plt.xlabel("t") plt.title("t" + "-error relation in {} norm".format(norm_type)) plt.ylabel("log(error})") plt.grid(True) plt.legend(loc='center left', bbox_to_anchor=(1, 0.8), shadow=True, ncol=1) plt.show()
def Verify2ndAccuracy(grid_size=[4, 8, 16, 32, 64, 128], axis: str = 't', norm_type: str = "L1"): def d(x): return 2 + np.cos(np.pi * x) def q(x): return 0.0 def bc0(t): return 1 + np.exp(-(np.pi**2) * t / 4) def bc1(t): return -0.5 * np.pi * (1 + np.exp(-(np.pi**2) * t / 4)) def ic(x): return 2 * np.cos(0.5 * np.pi * x) def f(x, t): result = -1/ 4 * (np.pi ** 2) * np.exp(- (np.pi ** 2) * t / 4) \ * np.cos(x * np.pi/2)*(-1 + 3 *(1 + np.exp((np.pi ** 2) * t / 4))* np.cos(x * np.pi)) return result def exact_sol(x, t): return (1 + np.exp(-(np.pi**2) * t / 4)) * np.cos(np.pi * x / 2) a = 0 b = 1 t_span = [0, 0.25] methods = ["CN", "Ralston"] method = methods[0] markdict = {4: 'x', 8: 'x', 16: 'x', 32: 'x', 64: 'x', 128: '-', 256: "x"} markoffsetdict = dict(zip(methods, ['', '-'])) errors2d = {"L1": [], "L2": [], "Linf": []} for N in grid_size: dt = 1 / (8 * N**2) BC0 = BoundaryCondition(a, type="D", constraint=bc0) BC1 = BoundaryCondition(b, type="N", constraint=bc1) spgrid = SpaceGrid(a, b, N + 1) xsample = np.linspace(a, b, N + 1) # initialize the SturmLiouville system and initial-boundary value problem ST = SturmLiouville(spgrid, d, q) ibvp = IBVP(ST=ST, Nonlinear=None, IC=ic, BCs=[BC0, BC1], rhs=f) # compute the discretization and matrix involved ibvp.compute() json_name = "sol node={}, dt={:.2g}, for {}.json".format(N, dt, method) print(json_name) import os exists = os.path.isfile('../data/{}'.format(json_name)) if exists: # Store configuration file values sol = Read_sol_json(json_name) else: # Keep presets if (method in ["CN", "BE"]): sol = ibvp.customize_solve(t_span=t_span, type=method, max_step=dt) else: sol = ibvp.ibvp_solve(t_span=t_span, type=method, max_step=dt) Write_sol_json(sol, json_name) ysample = np.abs(sol.y - np.array([[exact_sol(x, t) for t in sol.t] for x in xsample]))[1:, 1:] tsample = sol.t[1:] sliced_xsample = xsample[1:] sol1 = OdeResult(t=tsample, y=ysample) errors = FunctionNormAlong(sol=sol1, xsample=sliced_xsample, axis=axis, type=norm_type) errors_L1 = FunctionNormAlong(sol=sol1, xsample=sliced_xsample, axis=axis, type="L1") errors_L2 = FunctionNormAlong(sol=sol1, xsample=sliced_xsample, axis=axis, type="L2") errors_Linf = FunctionNormAlong(sol=sol1, xsample=sliced_xsample, axis=axis, type="Linf") errors2d["L1"].append( FunctionNorm1D(errors_L1.copy(), 1 / N, type="L1")) errors2d["L2"].append( FunctionNorm1D(errors_L2.copy(), 1 / N, type="L2")) errors2d["Linf"].append( FunctionNorm1D(errors_Linf.copy(), 1 / N, type="Linf")) if axis == "t": offset = {4: 1, 8: 1, 16: 1, 32: 1, 64: 2, 128: 4}[N] plt.semilogy(sliced_xsample[::offset], errors[::offset], markdict[N] + markoffsetdict[method], label=json_name[4:-5]) elif axis == "x": plt.semilogy(tsample, errors, markdict[N] + markoffsetdict[method], label=json_name[4:-5]) # powers = [pow(2, i) for i in range(1,5)] for i in [2, 4, 8, 16, 32]: plt.semilogy(sliced_xsample, errors * pow(i, 2), '--', label="{} times the node=128 error".format(i)) if axis == 't': plt.xlabel("x") plt.title( "Verification of 2nd oder accuracy in {} norm".format(norm_type)) else: plt.xlabel("t") plt.title( "Verification of 2nd oder accuracy in {} norm".format(norm_type)) plt.ylabel("log(error})") plt.grid(True) plt.legend(loc='center left', bbox_to_anchor=(1, 0.6), shadow=True, ncol=1) plt.show() for key in errors2d: plt.loglog(grid_size, errors2d[key], 'x-', label="total error in 2D-{} norm".format(key)) plt.loglog(grid_size, [4 * pow(g, -2) for g in grid_size], '-', label="base line of second oder arruracy") # plt.loglog(grid_size, [0.01 * pow(g, -4) for g in grid_size], '-', label="base line of fourth oder arruracy") plt.grid(True) plt.legend() plt.xlabel("node number N") plt.ylabel("total errors") plt.title( "Verification of 2nd order accuracy in 2D norms for {}".format(method)) plt.show()
def LTEplot3D(): def d(x): return 2 + np.cos(np.pi * x) def q(x): return 0.0 def bc0(t): return 1 + np.exp(-(np.pi**2) * t / 4) def bc1(t): return -0.5 * np.pi * (1 + np.exp(-(np.pi**2) * t / 4)) def ic(x): return 2 * np.cos(0.5 * np.pi * x) def f(x, t): result = -1/ 4 * (np.pi ** 2) * np.exp(- (np.pi ** 2) * t / 4) \ * np.cos(x * np.pi/2)*(-1 + 3 *(1 + np.exp((np.pi ** 2) * t / 4))* np.cos(x * np.pi)) return result def exact_sol(x, t): return (1 + np.exp(-(np.pi**2) * t / 4)) * np.cos(np.pi * x / 2) a = 0 b = 1 t_span = [0, 0.25] N = 10 dt = 0.00213 method = "Ralston" BC0 = BoundaryCondition(a, type="D", constraint=bc0) BC1 = BoundaryCondition(b, type="N", constraint=bc1) spgrid = SpaceGrid(a, b, N + 1) xsample = np.linspace(a, b, N + 1) # initialize the SturmLiouville system and initial-boundary value problem ST = SturmLiouville(spgrid, d, q) ibvp = IBVP(ST=ST, Nonlinear=None, IC=ic, BCs=[BC0, BC1], rhs=f) # compute the discretization and matrix involved ibvp.compute() if (method in ["CN", "BE"]): sol = ibvp.customize_solve(t_span=t_span, type=method, max_step=dt) else: sol = ibvp.ibvp_solve(t_span=t_span, type=method, max_step=dt) json_name = "sol_test node={}, dt={}, for {}".format(N, dt, method) Write_sol_json(sol, json_name + ".json") sol1 = Read_sol_json(json_name + ".json") PlotSpaceTimePDE(sol1, xsample, title="Space-Time-Solution node={}, dt={}, for {}".format( N, dt, method), tcount=50, xcount=1) ysample = np.log10( np.abs(sol1.y - np.array([[exact_sol(x, t) for t in sol1.t] for x in xsample]))) sol2 = OdeResult(t=sol1.t[1:], y=ysample[1:, 1:]) PlotSpaceTimePDE(sol2, xsample[1:], title="Space-Time-Error node={}, dt={} for {}".format( N, dt, method), tcount=50, xcount=1, error_plot=True)