def __init__(self, wavespeed=1.0, initial_condition=None, source_function=None): self.wavespeed = wavespeed if initial_condition is None: self.initial_condition = x_functions.Sine() else: self.initial_condition = initial_condition app = advection.Advection(wavespeed, source_function) max_wavespeed = wavespeed exact_solution = advection.ExactSolution(initial_condition, wavespeed) super().__init__( app, initial_condition, max_wavespeed, exact_solution )
def test_advection_operator(): # test that dg_operator acting on projected initial condition converges to # exact time derivative # will lose one order of accuracy for i in range(2): if i == 0: sin = x_functions.Sine() cos = x_functions.Cosine() initial_condition = x_functions.ComposedVector([sin, cos]) else: initial_condition = x_functions.Sine() wavespeed = 1.0 exact_solution = advection.ExactSolution(initial_condition, wavespeed) exact_time_derivative = advection.ExactTimeDerivative(exact_solution, wavespeed) initial_time_derivative = x_functions.FrozenT(exact_time_derivative, 0.0) app_ = advection.Advection(wavespeed) riemann_solver = riemann_solvers.LocalLaxFriedrichs(app_.flux_function) boundary_condition = boundary.Periodic() for basis_class in basis.BASIS_LIST: for num_basis_cpts in range(1, 5): basis_ = basis_class(num_basis_cpts) error_list = [] for num_elems in [20, 40]: mesh_ = mesh.Mesh1DUniform(0.0, 1.0, num_elems) dg_sol = basis_.project(initial_condition, mesh_) dg_operator = app_.get_explicit_operator( riemann_solver, boundary_condition ) F = dg_operator(0.0, dg_sol) error = math_utils.compute_error(F, initial_time_derivative) error_list.append(error) order = utils.convergence_order(error_list) assert order >= max([1.0, num_basis_cpts - 1])
def test_solution_operations(): # TODO: test operating two solutions with different bases cos = x_functions.Cosine() sin = x_functions.Sine() cos_sol = basis_.project(cos, mesh_) sin_sol = basis_.project(sin, mesh_) cosp2_sol = cos_sol + 2.0 sinp2_sol = sin_sol + 2.0 # addition def func(x): return cos(x) + 2.0 + sin(x) + 2.0 new_sol = cosp2_sol + sinp2_sol projected_sol = basis_.project(func, mesh_) error = (new_sol - projected_sol).norm() assert error <= tolerance # subtraction def func(x): return cos(x) + 2.0 - (sin(x) + 2.0) new_sol = cosp2_sol - sinp2_sol projected_sol = basis_.project(func, mesh_) error = (new_sol - projected_sol).norm() assert error <= tolerance # multiplication, division, and power won't be exact # multiplication def func(x): return (cos(x) + 2.0) * (sin(x) + 2.0) new_sol = cosp2_sol * sinp2_sol projected_sol = basis_.project(func, mesh_) error = (new_sol - projected_sol).norm() assert error <= tolerance_2 # division def func(x): return (cos(x) + 2.0) / (sin(x) + 2.0) new_sol = cosp2_sol / sinp2_sol projected_sol = basis_.project(func, mesh_) error = (new_sol - projected_sol).norm() assert error <= tolerance_2 # power def func(x): return (cos(x) + 2.0) ** (sin(x) + 2.0) new_sol = cosp2_sol ** sinp2_sol projected_sol = basis_.project(func, mesh_) error = (new_sol - projected_sol).norm() assert error <= tolerance_2
def test_bounds_limiter_sine(): bounds_limiter = shock_capturing_limiters.BoundsLimiter() basis_ = basis.LegendreBasis1D(3) mesh_ = mesh.Mesh1DUniform(0, 1, 10) func = x_functions.Sine(1.0, 1.0, 0.0) dg_solution = basis_.project(func, mesh_) boundary_condition = boundary.Periodic() app_ = advection.Advection() problem_ = problem.Problem(app_, dg_solution) problem_.boundary_condition = boundary_condition initial_solution = dg_solution.copy() limited_solution = bounds_limiter.limit_solution(problem, dg_solution) # limited solution should be same as initial solution as smooth assert (limited_solution - initial_solution).norm() == 0.0 func = x_functions.Sine(1.0, 10.0, 0.0) dg_solution = basis_.project(func, mesh_) initial_solution = dg_solution.copy() limited_solution = bounds_limiter.limit_solution(problem, dg_solution) # with higher wavenumber the limiter should chop off maxima assert limited_solution.norm() <= initial_solution.norm()
def periodic_exact_solution(wavenumber=1.0, diffusion_constant=1.0): # q_t(x, t) - d * q_xx(x, t) = 0 # q(x, 0) = sin(2 pi lambda x) # q(n, t) = q(m, t), q_x(n, t) = q_x(m, t) for integers n < m # exact solution with periodic boundaries # q(x, t) = e^{-4 pi^2 lambda^2 t} sin(2 pi lambda x) initial_condition = x_functions.Sine(wavenumber) diffusion = Diffusion( initial_condition=initial_condition, diffusion_constant=diffusion_constant ) r = -4.0 * diffusion_constant * np.power(np.pi * wavenumber, 2) diffusion.exact_solution = xt_functions.ExponentialFunction( initial_condition, r ) return diffusion
def test_linearized_mms_ldg_matrix_independence_from_dg_solution(): g = x_functions.Sine(offset=2.0) r = -4.0 * np.power(np.pi, 2) exact_solution = flux_functions.ExponentialFunction(g, r) t_initial = 0.0 bc = boundary.Periodic() p_func = convection_diffusion.NonlinearDiffusion.linearized_manufactured_solution for diffusion_function in diffusion_functions: problem = p_func(exact_solution, diffusion_function) for basis_class in basis.BASIS_LIST: for num_basis_cpts in range(1, 4): basis_ = basis_class(num_basis_cpts) mesh_ = mesh.Mesh1DUniform(0.0, 1.0, 20) sine_dg = basis_.project(x_functions.Sine(offset=2.0), mesh_) cosine_dg = basis_.project(x_functions.Cosine(offset=2.0), mesh_) tuple_ = problem.ldg_matrix(sine_dg, t_initial, bc, bc) sine_matrix = tuple_[0] sine_vector = tuple_[1] tuple_ = problem.ldg_matrix(cosine_dg, t_initial, bc, bc) cosine_matrix = tuple_[0] cosine_vector = tuple_[1] assert np.linalg.norm(sine_matrix - cosine_matrix) <= tolerance assert np.linalg.norm(sine_vector - cosine_vector) <= tolerance
def test_ldg_operator_equal_matrix(): f = x_functions.Sine() t = 0.0 for bc in [boundary.Periodic(), boundary.Extrapolation()]: for num_basis_cpts in range(1, 6): for basis_class in basis.BASIS_LIST: basis_ = basis_class(num_basis_cpts) mesh_ = mesh.Mesh1DUniform(0.0, 1.0, 10) dg_solution = basis_.project(f, mesh_) L = diffusion.ldg_operator(dg_solution, t, bc, bc) dg_vector = dg_solution.to_vector() tuple_ = diffusion.ldg_matrix(dg_solution, t, bc, bc) matrix = tuple_[0] vector = tuple_[1] error = np.linalg.norm(L.to_vector() - np.matmul(matrix, dg_vector) - vector) assert error <= tolerance
def test_neumann(): boundary_derivative_function = flux_functions.Zero() bc = boundary.Neumann(boundary_derivative_function) basis_ = basis.LegendreBasis1D(3) mesh_ = mesh.Mesh1DUniform(0.0, 1.0, 10) f = x_functions.Sine() dg_solution = basis_.project(f, mesh_) problem = smooth_scalar_example.SmoothScalarExample(1.0, f) riemann_solver = riemann_solvers.LocalLaxFriedrichs(problem) boundary_faces = mesh_.boundary_faces t = 0.0 flux = bc.evaluate_boundary(dg_solution, boundary_faces[0], riemann_solver, t) assert flux is not None
def test_interior(): bc = boundary.Extrapolation() basis_ = basis.LegendreBasis1D(3) mesh_ = mesh.Mesh1DUniform(0.0, 1.0, 10) f = x_functions.Sine() dg_solution = basis_.project(f, mesh_) problem = smooth_scalar_example.SmoothScalarExample(1.0, f) riemann_solver = riemann_solvers.LocalLaxFriedrichs(problem) boundary_faces = mesh_.boundary_faces t = 0.0 flux = bc.evaluate_boundary(dg_solution, boundary_faces[0], riemann_solver, t) x = mesh_.get_face_position(boundary_faces[0]) assert flux == dg_solution(x)
def test_ldg_matrix_irk(): p_func = convection_hyper_diffusion.HyperDiffusion.periodic_exact_solution problem = p_func(x_functions.Sine(offset=2.0), diffusion_constant=1.0) t_initial = 0.0 t_final = 0.1 bc = boundary.Periodic() exact_solution = lambda x: problem.exact_solution(x, t_final) for num_basis_cpts in range(1, 3): irk = implicit_runge_kutta.get_time_stepper(num_basis_cpts) for basis_class in basis.BASIS_LIST: basis_ = basis_class(num_basis_cpts) error_list = [] # constant matrix n = 20 for num_elems in [n, 2 * n]: mesh_ = mesh.Mesh1DUniform(0.0, 1.0, num_elems) delta_t = mesh_.delta_x / 5 dg_solution = basis_.project(problem.initial_condition, mesh_) # constant matrix time doesn't matter tuple_ = problem.ldg_matrix(dg_solution, t_initial, bc, bc, bc, bc) matrix = tuple_[0] vector = tuple_[1] rhs_function = problem.get_implicit_operator(bc, bc, bc, bc) solve_function = time_stepping.get_solve_function_constant_matrix( matrix, vector) new_solution = time_stepping.time_step_loop_implicit( dg_solution, t_initial, t_final, delta_t, irk, rhs_function, solve_function, ) dg_error = math_utils.compute_dg_error(new_solution, exact_solution) error = dg_error.norm() error_list.append(error) # plot.plot_dg_1d(new_solution, function=exact_solution) # plot.plot(dg_error) order = utils.convergence_order(error_list) # if not already at machine error if error_list[0] > 1e-10 and error_list[1] > 1e-10: assert order >= num_basis_cpts
def test_periodic(): bc = boundary.Periodic() basis_ = basis.LegendreBasis1D(3) mesh_ = mesh.Mesh1DUniform(0.0, 1.0, 10) f = x_functions.Sine() dg_solution = basis_.project(f, mesh_) problem = smooth_scalar_example.SmoothScalarExample(1.0, f) riemann_solver = riemann_solvers.LocalLaxFriedrichs(problem) boundary_faces = mesh_.boundary_faces t = 0.0 flux_0 = bc.evaluate_boundary(dg_solution, boundary_faces[0], riemann_solver, t) flux_1 = bc.evaluate_boundary(dg_solution, boundary_faces[1], riemann_solver, t) # fluxes should be the same assert flux_0 == flux_1
def test_exponential_function(): g = x_functions.Sine() r = 1.0 xt_function = xt_functions.ExponentialFunction(g, r) utils.check_to_from_dict(xt_function, xt_functions) # should be able to call with (x, t) and (q, x, t) q = 0.0 x = 0.5 t = 0.1 assert xt_function(x, t) is not None assert xt_function(q, x, t) is not None assert xt_function(q, x, t) == xt_function(x, t) assert xt_function.q_derivative(q, x, t) is not None assert xt_function.x_derivative(q, x, t) is not None assert xt_function.x_derivative(x, t) is not None assert xt_function.x_derivative(x, t) == xt_function.x_derivative(q, x, t) assert xt_function.t_derivative(q, x, t) is not None assert xt_function.t_derivative(x, t) is not None assert xt_function.t_derivative(x, t) == xt_function.t_derivative(q, x, t)
def periodic_exact_solution(initial_condition=None, diffusion_constant=1.0): # q_t(x, t) + d q_xxxx(x, t) = 0 # q(x, 0) = amplitude * f(2 pi lambda x) + offset, where f is sin or cos # periodic boundary conditions # exact solution is then # q(x, t) = amplitude * e^{- d (2 pi lambda)^4 t} f(2 pi lambda x) + offset if initial_condition is None: initial_condition = x_functions.Sine(offset=2.0) hyper_diffusion = HyperDiffusion(None, initial_condition, diffusion_constant) r = ( -1.0 * diffusion_constant * np.power(2.0 * np.pi * initial_condition.wavenumber, 4) ) g = copy.deepcopy(initial_condition) g.offset = 0.0 hyper_diffusion.exact_solution = flux_functions.ExponentialFunction( g, r, initial_condition.offset ) return hyper_diffusion
def test_linearized_mms_operator_matrix_equivalency(): g = x_functions.Sine(offset=2.0) r = -4.0 * np.power(np.pi, 2) exact_solution = flux_functions.ExponentialFunction(g, r) t = 0.0 bc = boundary.Periodic() p_func = convection_diffusion.NonlinearDiffusion.linearized_manufactured_solution for diffusion_function in diffusion_functions: problem = p_func(exact_solution, diffusion_function) for basis_class in basis.BASIS_LIST: for num_basis_cpts in range(1, 4): basis_ = basis_class(num_basis_cpts) mesh_ = mesh.Mesh1DUniform(0.0, 1.0, 20) dg_solution = basis_.project(problem.initial_condition, mesh_) L = problem.ldg_operator(dg_solution, t, bc, bc) tuple_ = problem.ldg_matrix(dg_solution, t, bc, bc) matrix = tuple_[0] vector = tuple_[1] dg_vector = dg_solution.to_vector() error = np.linalg.norm(L.to_vector() - np.matmul(matrix, dg_vector) - vector) assert error < tolerance
def test_matrix_operator_equivalency(): t = 0.0 for bc in [boundary.Periodic(), boundary.Extrapolation()]: for nonlinear_diffusion in test_problems: nonlinear_diffusion.initial_condition = x_functions.Sine( offset=2.0) for num_basis_cpts in range(1, 6): for basis_class in basis.BASIS_LIST: basis_ = basis_class(num_basis_cpts) mesh_ = mesh.Mesh1DUniform(0.0, 1.0, 10) dg_solution = basis_.project( nonlinear_diffusion.initial_condition, mesh_) L = nonlinear_diffusion.ldg_operator( dg_solution, t, bc, bc) dg_vector = dg_solution.to_vector() tuple_ = nonlinear_diffusion.ldg_matrix( dg_solution, t, bc, bc) matrix = tuple_[0] vector = tuple_[1] error = np.linalg.norm(L.to_vector() - np.matmul(matrix, dg_vector) - vector) assert error <= tolerance
def test_dg_operator(): # test that dg_operator converges to exact_time_derivative in smooth case initial_condition = x_functions.Sine(offset=2.0) max_wavespeed = 3.0 problem = smooth_example.SmoothExample(initial_condition, max_wavespeed) riemann_solver = riemann_solvers.LocalLaxFriedrichs(problem) boundary_condition = boundary.Periodic() x_left = 0.0 x_right = 1.0 exact_time_derivative = burgers.ExactTimeDerivative( problem.initial_condition) exact_time_derivative_initial = x_functions.FrozenT( exact_time_derivative, 0.0) for basis_class in basis.BASIS_LIST: for num_basis_cpts in range(1, 5): basis_ = basis_class(num_basis_cpts) error_list = [] for num_elems in [40, 80]: mesh_ = mesh.Mesh1DUniform(x_left, x_right, num_elems) dg_solution = basis_.project(problem.initial_condition, mesh_) explicit_operator = problem.app_.get_explicit_operator( riemann_solver, boundary_condition) dg_time_derivative = explicit_operator(0.0, dg_solution) error = math_utils.compute_error( dg_time_derivative, exact_time_derivative_initial) error_list.append(error) order = test_utils.convergence_order(error_list) if num_basis_cpts > 1: assert order >= num_basis_cpts - 1 else: assert order >= 1
def __init__(self, wavespeed=1.0, initial_condition=None, source_function=None): self.wavespeed = wavespeed if initial_condition is None: initial_condition = x_functions.Sine() app = advection.Advection(wavespeed, source_function) max_wavespeed = wavespeed exact_solution = advection.ExactSolution(initial_condition, wavespeed) exact_operator = advection.ExactOperator(exact_solution, wavespeed, source_function) exact_time_derivative = advection.ExactTimeDerivative( exact_solution, wavespeed, source_function) super().__init__( app, initial_condition, max_wavespeed, exact_solution, exact_operator, exact_time_derivative, )
from apps.onedimensional.advection import advection from pydogpack.utils import x_functions from pydogpack import main from pydogpack.visualize import plot class SmoothSystemExample(problem.Problem): def __init__(self, wavespeed=1.0, initial_condition=None, source_function=None): self.wavespeed = wavespeed if initial_condition is None: self.initial_condition = x_functions.Sine() else: self.initial_condition = initial_condition app = advection.Advection(wavespeed, source_function) max_wavespeed = wavespeed exact_solution = advection.ExactSolution(initial_condition, wavespeed) super().__init__( app, initial_condition, max_wavespeed, exact_solution ) if __name__ == "__main__": wavespeed = 1.0 initial_condition = x_functions.ComposedVector( [x_functions.Sine(), x_functions.Cosine()] ) problem = SmoothSystemExample(wavespeed, initial_condition) final_solution = main.run(problem)
from apps.onedimensional.advection.smoothscalarexample import smooth_scalar_example as asse from apps.onedimensional.burgers import burgers from apps.onedimensional.linearsystem.smoothexample import smooth_example as lsse from pydogpack.riemannsolvers import riemann_solvers from pydogpack.utils import x_functions import numpy as np tolerance = 1e-12 advection_problem = asse.SmoothScalarExample(1.0, x_functions.Sine()) # burgers_problem = None ic = x_functions.ComposedVector([x_functions.Sine(), x_functions.Cosine()]) linear_system_problem = lsse.SmoothExample(np.array([[1, 5], [5, 1]]), ic) # shallow_water_problem = None problem_list = [ advection_problem, # burgers_problem, linear_system_problem, # shallow_water_problem, ] default_q_list = [ 0.5, # 0.5, np.array([0.5, 0.5]), # np.array([0.5, 0.5]), ] def sample_problems(riemann_solver_class, do_check_monotonicity=True): for i in range(len(problem_list)):
from apps import app from apps.onedimensional.convectiondiffusion import convection_diffusion from apps.onedimensional.convectionhyperdiffusion import ldg from pydogpack.utils import dg_utils from pydogpack.utils import flux_functions from pydogpack.utils import x_functions from pydogpack.utils import xt_functions from inspect import signature import numpy as np import copy # solution should be positive so initial condition should default to positive default_initial_condition = x_functions.Sine(offset=2.0) # represents q_t + (f(q, x))_x = -(g(q) q_xxx)_x + s(x) # solution needs to be positive to avoid backward diffusion class ConvectionHyperDiffusion(app.App): def __init__( self, flux_function=None, diffusion_function=None, source_function=None, initial_condition=default_initial_condition, max_wavespeed=1.0, ): # default to linear hyper diffusion, with diffusion constant 1 if diffusion_function is None: self.diffusion_function = flux_functions.Polynomial(degree=0) else:
exact_solution, exact_operator, exact_time_derivative, ) class ExactSolution(xt_functions.XTFunction): # TODO: Add source function def __init__(self, initial_condition): self.initial_condition = initial_condition def function(self, x, t): # TODO: does this work if x is array # solve characteristics # find xi that satisfies x = initial_condition(xi) * t + xi # then exact solution is u(x, t) = initial_condition(xi) def xi_function(xi): return self.initial_condition(xi) * t + xi - x # if exact solution has shocked, then newton will throw error # TODO: could catch exception xi = optimize.newton(xi_function, x) return self.initial_condition(xi) if __name__ == "__main__": initial_condition = x_functions.Sine() max_wavespeed = 1.0 problem = SmoothExample(initial_condition, max_wavespeed) final_solution = main.run(problem)
def test_sine(): sine = x_functions.Sine() check_x_function(sine)