def run_convergence_test_advec(dtype, flux_type, random_partition, mesh_gen, debug_output=False): """Test whether 2/3D advection actually converges""" from hedge.timestep import RK4TimeStepper from hedge.tools import EOCRecorder from math import sin from hedge.data import TimeDependentGivenFunction from hedge.visualization import SiloVisualizer from hedge.backends import guess_run_context rcon = guess_run_context(["mpi"]) # note: x component must remain zero because x-periodicity is used v = np.array([0.0, 0.9, 0.3]) def f(x): return sin(x) def u_analytic(x, el, t): return f( (np.dot(-v[:dims], x) / la.norm(v[:dims]) + t * la.norm(v[:dims]))) def boundary_tagger(vertices, el, face_nr, points): face_normal = el.face_normals[face_nr] if np.dot(face_normal, v[:len(face_normal)]) < 0: return ["inflow"] else: return ["outflow"] mesh = mesh_gen(boundary_tagger) eoc_rec = EOCRecorder() if random_partition: # Distribute elements randomly across nodes. # This is bad, efficiency-wise, but it puts stress # on the parallel implementation, which is desired here. # Another main point of this is to force the code to split # a periodic face pair across nodes. from random import choice partition = [choice(rcon.ranks) for el in mesh.elements] else: partition = None for order in [1, 2, 3, 4]: if rcon.is_head_rank: mesh_data = rcon.distribute_mesh(mesh, partition) else: mesh_data = rcon.receive_mesh() dims = mesh.points.shape[1] discr = rcon.make_discretization(mesh_data, order=order, default_scalar_type=dtype) op = StrongAdvectionOperator( v[:dims], inflow_u=TimeDependentGivenFunction(u_analytic), flux_type=flux_type) if debug_output: vis = SiloVisualizer(discr, rcon) u = discr.interpolate_volume_function( lambda x, el: u_analytic(x, el, 0)) ic = u.copy() if debug_output and rcon.is_head_rank: print "#elements=%d" % len(mesh.elements) test_name = "test-%s-o%d-m%s-r%s" % ( flux_type, order, mesh_gen.__name__, random_partition) rhs = op.bind(discr) stepper = RK4TimeStepper(dtype=dtype) from hedge.timestep import times_and_steps final_time = 1 step_it = times_and_steps(final_time=final_time, max_dt_getter=lambda t: op.estimate_timestep( discr, stepper=stepper, t=t, fields=u)) for step, t, dt in step_it: u = stepper(u, t, dt, rhs) assert u.dtype == dtype u_true = discr.interpolate_volume_function( lambda x, el: u_analytic(x, el, final_time)) error = u - u_true l2_error = discr.norm(error) if debug_output: visf = vis.make_file(test_name + "-final") vis.add_data(visf, [("u", u), ("u_true", u_true), ("ic", ic)]) visf.close() eoc_rec.add_data_point(order, l2_error) if debug_output and rcon.is_head_rank: print "%s\n%s\n" % (flux_type.upper(), "-" * len(flux_type)) print eoc_rec.pretty_print(abscissa_label="Poly. Order", error_label="L2 Error") assert eoc_rec.estimate_order_of_convergence()[0, 1] > 3 assert eoc_rec.estimate_order_of_convergence(2)[-1, 1] > 7
def test_convergence_advec_2d(): """Test whether 2D advection actually converges""" import pyublas # noqa from hedge.mesh.generator import make_disk_mesh, make_regular_rect_mesh from hedge.discretization.local import TriangleDiscretization from hedge.timestep import RK4TimeStepper from hedge.tools import EOCRecorder from math import sin, pi from hedge.models.advection import StrongAdvectionOperator from hedge.data import TimeDependentGivenFunction v = numpy.array([0.27, 0]) norm_a = la.norm(v) from numpy import dot def f(x): return sin(x) def u_analytic(x, el, t): return f((-dot(v, x) / norm_a + t * norm_a)) def boundary_tagger(vertices, el, face_nr, all_v): if dot(el.face_normals[face_nr], v) < 0: return ["inflow"] else: return ["outflow"] for mesh in [ # non-periodic make_disk_mesh(r=pi, boundary_tagger=boundary_tagger, max_area=0.5), # periodic make_regular_rect_mesh( a=(0, 0), b=(2 * pi, 1), n=(8, 4), periodicity=(True, False), boundary_tagger=boundary_tagger, ) ]: for flux_type in StrongAdvectionOperator.flux_types: eoc_rec = EOCRecorder() for order in [1, 2, 3, 4, 5, 6]: discr = discr_class( mesh, TriangleDiscretization(order), debug=discr_class.noninteractive_debug_flags()) op = StrongAdvectionOperator( v, inflow_u=TimeDependentGivenFunction(u_analytic), flux_type=flux_type) u = discr.interpolate_volume_function( lambda x, el: u_analytic(x, el, 0)) stepper = RK4TimeStepper() dt = op.estimate_timestep(discr, stepper=stepper) nsteps = int(1 / dt) rhs = op.bind(discr) for step in range(nsteps): u = stepper(u, step * dt, dt, rhs) u_true = discr.interpolate_volume_function( lambda x, el: u_analytic(x, el, nsteps * dt)) error = u - u_true error_l2 = discr.norm(error) eoc_rec.add_data_point(order, error_l2) if False: print "%s\n%s\n" % (flux_type.upper(), "-" * len(flux_type)) print eoc_rec.pretty_print(abscissa_label="Poly. Order", error_label="L2 Error") assert eoc_rec.estimate_order_of_convergence()[0, 1] > 4 assert eoc_rec.estimate_order_of_convergence(2)[-1, 1] > 10
def test_symmetry_preservation_2d(): """Test whether we preserve symmetry in a symmetric 2D advection problem""" from numpy import dot def make_mesh(): array = numpy.array # # 1---8---2 # |7 /|\ 1| # | / | \ | # |/ 6|0 \| # 5---4---7 # |\ 5|3 /| # | \ | / | # |4 \|/ 2| # 0---6---3 # points = [ array([-0.5, -0.5]), array([-0.5, 0.5]), array([0.5, 0.5]), array([0.5, -0.5]), array([0.0, 0.0]), array([-0.5, 0.0]), array([0.0, -0.5]), array([0.5, 0.0]), array([0.0, 0.5]) ] elements = [ [8, 7, 4], [8, 7, 2], [6, 7, 3], [7, 4, 6], [5, 6, 0], [5, 6, 4], [5, 8, 4], [1, 5, 8], ] def boundary_tagger(vertices, el, face_nr, all_v): if dot(el.face_normals[face_nr], v) < 0: return ["inflow"] else: return ["outflow"] from hedge.mesh import make_conformal_mesh return make_conformal_mesh(points, elements, boundary_tagger) from hedge.discretization import SymmetryMap from hedge.timestep import RK4TimeStepper from hedge.models.advection import StrongAdvectionOperator from hedge.data import TimeDependentGivenFunction v = numpy.array([-1, 0]) mesh = make_mesh() discr = discr_class(mesh, order=4, debug=discr_class.noninteractive_debug_flags()) #ref_discr = DynamicDiscretization(mesh, order=4) def f(x): if x < 0.5: return 0 else: return (x - 0.5) #def f(x): #return sin(5*x) def u_analytic(x, el, t): return f(-dot(v, x) + t) u = discr.interpolate_volume_function(lambda x, el: u_analytic(x, el, 0)) sym_map = SymmetryMap(discr, lambda x: numpy.array([x[0], -x[1]]), { 0: 3, 2: 1, 5: 6, 7: 4 }) for flux_type in StrongAdvectionOperator.flux_types: stepper = RK4TimeStepper() op = StrongAdvectionOperator( v, inflow_u=TimeDependentGivenFunction(u_analytic), flux_type=flux_type) dt = op.estimate_timestep(discr, stepper=stepper) nsteps = int(1 / dt) rhs = op.bind(discr) #test_comp = [ "bflux"] #test_rhs = op.bind(discr, test_comp) #ref_rhs = op.bind(ref_discr, test_comp) for step in xrange(nsteps): u = stepper(u, step * dt, dt, rhs) sym_error_u = u - sym_map(u) sym_error_u_l2 = discr.norm(sym_error_u) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test-%s-%04d" % (flux_type, step)) vis.add_data( visf, [ ("u", u), ("sym_u", sym_map(u)), ("sym_diff", u - sym_map(u)), ("rhs", rhs(step * dt, u)), #("rhs_test", test_rhs(step*dt, u)), #("rhs_ref", ref_rhs(step*dt, u)), #("rhs_diff", test_rhs(step*dt, u)-ref_rhs(step*dt, u)), ]) print sym_error_u_l2 assert sym_error_u_l2 < 4e-15
def run_convergence_test_advec(dtype, debug_output=False): """Test whether 2/3D advection actually converges""" from hedge.mesh.generator import make_ball_mesh, make_box_mesh, make_rect_mesh from hedge.timestep import RK4TimeStepper from hedge.tools import EOCRecorder from math import sin, pi, sqrt from hedge.models.advection import StrongAdvectionOperator from hedge.data import TimeDependentGivenFunction from hedge.visualization import SiloVisualizer from hedge.backends import guess_run_context rcon = guess_run_context(["mpi"]) # note: x component must remain zero because x-periodicity is used v = numpy.array([0.0,0.9,0.3]) def f(x): return sin(x) def u_analytic(x, el, t): return f((numpy.dot(-v[:dims],x)/la.norm(v[:dims])+t*la.norm(v[:dims]))) def boundary_tagger(vertices, el, face_nr, points): face_normal = el.face_normals[face_nr] if numpy.dot(face_normal, v[:len(face_normal)]) < 0: return ["inflow"] else: return ["outflow"] for i_mesh, mesh in enumerate([ # 2D semiperiodic make_rect_mesh(b=(2*pi,3), max_area=0.4, periodicity=(True, False), subdivisions=(5,10), boundary_tagger=boundary_tagger, ), # 3D x-periodic make_box_mesh((0,0,0), (2*pi, 2, 2), max_volume=0.4, periodicity=(True, False, False), boundary_tagger=boundary_tagger, ), # non-periodic make_ball_mesh(r=pi, boundary_tagger=boundary_tagger, max_volume=0.7), ]): for flux_type in StrongAdvectionOperator.flux_types: for random_partition in [True, False]: eoc_rec = EOCRecorder() if random_partition: # Distribute elements randomly across nodes. # This is bad, efficiency-wise, but it puts stress # on the parallel implementation, which is desired here. # Another main point of this is to force the code to split # a periodic face pair across nodes. from random import choice partition = [choice(rcon.ranks) for el in mesh.elements] else: partition = None for order in [1,2,3,4]: if rcon.is_head_rank: mesh_data = rcon.distribute_mesh(mesh, partition) else: mesh_data = rcon.receive_mesh() dims = mesh.points.shape[1] discr = rcon.make_discretization(mesh_data, order=order, default_scalar_type=dtype) op = StrongAdvectionOperator(v[:dims], inflow_u=TimeDependentGivenFunction(u_analytic), flux_type=flux_type) if debug_output: vis = SiloVisualizer(discr, rcon) u = discr.interpolate_volume_function( lambda x, el: u_analytic(x, el, 0)) ic = u.copy() if debug_output and rcon.is_head_rank: print "#elements=%d" % len(mesh.elements) test_name = "test-%s-o%d-m%d-r%s" % ( flux_type, order, i_mesh, random_partition) rhs = op.bind(discr) stepper = RK4TimeStepper(dtype=dtype) from hedge.timestep import times_and_steps final_time = 1 step_it = times_and_steps( final_time=final_time, max_dt_getter=lambda t: op.estimate_timestep(discr, stepper=stepper, t=t, fields=u)) for step, t, dt in step_it: u = stepper(u, t, dt, rhs) assert u.dtype == dtype u_true = discr.interpolate_volume_function( lambda x, el: u_analytic(x, el, final_time)) error = u-u_true l2_error = discr.norm(error) if debug_output: visf = vis.make_file(test_name+"-final") vis.add_data(visf, [ ("u", u), ("u_true", u_true), ("ic", ic)]) visf.close() eoc_rec.add_data_point(order, l2_error) if debug_output and rcon.is_head_rank: print "%s\n%s\n" % (flux_type.upper(), "-" * len(flux_type)) print eoc_rec.pretty_print(abscissa_label="Poly. Order", error_label="L2 Error") assert eoc_rec.estimate_order_of_convergence()[0,1] > 3 assert eoc_rec.estimate_order_of_convergence(2)[-1,1] > 7
def test_convergence_advec_2d(): """Test whether 2D advection actually converges""" import pyublas from hedge.mesh.generator import make_disk_mesh, make_regular_rect_mesh from hedge.discretization.local import TriangleDiscretization from hedge.timestep import RK4TimeStepper from hedge.tools import EOCRecorder from math import sin, pi, sqrt from hedge.models.advection import StrongAdvectionOperator from hedge.data import TimeDependentGivenFunction v = numpy.array([0.27, 0]) norm_a = la.norm(v) from numpy import dot def f(x): return sin(x) def u_analytic(x, el, t): return f((-dot(v, x) / norm_a + t * norm_a)) def boundary_tagger(vertices, el, face_nr, all_v): if dot(el.face_normals[face_nr], v) < 0: return ["inflow"] else: return ["outflow"] for mesh in [ # non-periodic make_disk_mesh(r=pi, boundary_tagger=boundary_tagger, max_area=0.5), # periodic make_regular_rect_mesh( a=(0, 0), b=(2 * pi, 1), n=(8, 4), periodicity=(True, False), boundary_tagger=boundary_tagger ), ]: for flux_type in StrongAdvectionOperator.flux_types: eoc_rec = EOCRecorder() for order in [1, 2, 3, 4, 5, 6]: discr = discr_class(mesh, TriangleDiscretization(order), debug=discr_class.noninteractive_debug_flags()) op = StrongAdvectionOperator(v, inflow_u=TimeDependentGivenFunction(u_analytic), flux_type=flux_type) u = discr.interpolate_volume_function(lambda x, el: u_analytic(x, el, 0)) stepper = RK4TimeStepper() dt = op.estimate_timestep(discr, stepper=stepper) nsteps = int(1 / dt) rhs = op.bind(discr) for step in range(nsteps): u = stepper(u, step * dt, dt, rhs) u_true = discr.interpolate_volume_function(lambda x, el: u_analytic(x, el, nsteps * dt)) error = u - u_true error_l2 = discr.norm(error) eoc_rec.add_data_point(order, error_l2) if False: print "%s\n%s\n" % (flux_type.upper(), "-" * len(flux_type)) print eoc_rec.pretty_print(abscissa_label="Poly. Order", error_label="L2 Error") assert eoc_rec.estimate_order_of_convergence()[0, 1] > 4 assert eoc_rec.estimate_order_of_convergence(2)[-1, 1] > 10
def test_symmetry_preservation_2d(): """Test whether we preserve symmetry in a symmetric 2D advection problem""" from numpy import dot def make_mesh(): array = numpy.array # # 1---8---2 # |7 /|\ 1| # | / | \ | # |/ 6|0 \| # 5---4---7 # |\ 5|3 /| # | \ | / | # |4 \|/ 2| # 0---6---3 # points = [ array([-0.5, -0.5]), array([-0.5, 0.5]), array([0.5, 0.5]), array([0.5, -0.5]), array([0.0, 0.0]), array([-0.5, 0.0]), array([0.0, -0.5]), array([0.5, 0.0]), array([0.0, 0.5]), ] elements = [[8, 7, 4], [8, 7, 2], [6, 7, 3], [7, 4, 6], [5, 6, 0], [5, 6, 4], [5, 8, 4], [1, 5, 8]] def boundary_tagger(vertices, el, face_nr, all_v): if dot(el.face_normals[face_nr], v) < 0: return ["inflow"] else: return ["outflow"] from hedge.mesh import make_conformal_mesh return make_conformal_mesh(points, elements, boundary_tagger) from hedge.discretization import SymmetryMap from hedge.discretization.local import TriangleDiscretization from hedge.timestep import RK4TimeStepper from math import sqrt, sin from hedge.models.advection import StrongAdvectionOperator from hedge.data import TimeDependentGivenFunction v = numpy.array([-1, 0]) mesh = make_mesh() discr = discr_class(mesh, order=4, debug=discr_class.noninteractive_debug_flags()) # ref_discr = DynamicDiscretization(mesh, order=4) def f(x): if x < 0.5: return 0 else: return x - 0.5 # def f(x): # return sin(5*x) def u_analytic(x, el, t): return f(-dot(v, x) + t) u = discr.interpolate_volume_function(lambda x, el: u_analytic(x, el, 0)) sym_map = SymmetryMap(discr, lambda x: numpy.array([x[0], -x[1]]), {0: 3, 2: 1, 5: 6, 7: 4}) for flux_type in StrongAdvectionOperator.flux_types: stepper = RK4TimeStepper() op = StrongAdvectionOperator(v, inflow_u=TimeDependentGivenFunction(u_analytic), flux_type=flux_type) dt = op.estimate_timestep(discr, stepper=stepper) nsteps = int(1 / dt) rhs = op.bind(discr) # test_comp = [ "bflux"] # test_rhs = op.bind(discr, test_comp) # ref_rhs = op.bind(ref_discr, test_comp) for step in xrange(nsteps): u = stepper(u, step * dt, dt, rhs) sym_error_u = u - sym_map(u) sym_error_u_l2 = discr.norm(sym_error_u) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test-%s-%04d" % (flux_type, step)) vis.add_data( visf, [ ("u", u), ("sym_u", sym_map(u)), ("sym_diff", u - sym_map(u)), ("rhs", rhs(step * dt, u)), ("rhs_test", test_rhs(step * dt, u)), ("rhs_ref", ref_rhs(step * dt, u)), ("rhs_diff", test_rhs(step * dt, u) - ref_rhs(step * dt, u)), ], ) print sym_error_u_l2 assert sym_error_u_l2 < 4e-15