def test_projection(): """Test whether projection between different orders works""" from hedge.mesh.generator import make_disk_mesh from hedge.discretization import Projector from hedge.discretization.local import TriangleDiscretization from hedge.tools import EOCRecorder from math import sin, pi, sqrt from numpy import dot a = numpy.array([1, 3]) def u_analytic(x, el): return sin(dot(a, x)) mesh = make_disk_mesh(r=pi, max_area=0.5) discr2 = discr_class(mesh, TriangleDiscretization(2), debug=discr_class.noninteractive_debug_flags()) discr5 = discr_class(mesh, TriangleDiscretization(5), debug=discr_class.noninteractive_debug_flags()) p2to5 = Projector(discr2, discr5) p5to2 = Projector(discr5, discr2) u2 = discr2.interpolate_volume_function(u_analytic) u2_i = p5to2(p2to5(u2)) assert discr2.norm(u2 - u2_i) < 3e-15
def test_projection(): """Test whether projection between different orders works""" from hedge.mesh.generator import make_disk_mesh from hedge.discretization import Projector from hedge.discretization.local import TriangleDiscretization from math import sin, pi from numpy import dot a = numpy.array([1, 3]) def u_analytic(x, el): return sin(dot(a, x)) mesh = make_disk_mesh(r=pi, max_area=0.5) discr2 = discr_class(mesh, TriangleDiscretization(2), debug=discr_class.noninteractive_debug_flags()) discr5 = discr_class(mesh, TriangleDiscretization(5), debug=discr_class.noninteractive_debug_flags()) p2to5 = Projector(discr2, discr5) p5to2 = Projector(discr5, discr2) u2 = discr2.interpolate_volume_function(u_analytic) u2_i = p5to2(p2to5(u2)) assert discr2.norm(u2 - u2_i) < 3e-15
def test_tri_mass_mat_trig(): """Check the integral of some trig functions on a square using the mass matrix""" from hedge.mesh.generator import make_square_mesh from hedge.discretization.local import TriangleDiscretization from math import sqrt, pi, cos, sin mesh = make_square_mesh(a=-pi, b=pi, max_area=(2 * pi / 10) ** 2 / 2) discr = discr_class(mesh, TriangleDiscretization(8), debug=discr_class.noninteractive_debug_flags()) f = discr.interpolate_volume_function(lambda x, el: cos(x[0]) ** 2 * sin(x[1]) ** 2) ones = discr.interpolate_volume_function(lambda x, el: 1) from hedge.optemplate import MassOperator mass_op = MassOperator() num_integral_1 = numpy.dot(ones, mass_op.apply(discr, f)) num_integral_2 = numpy.dot(f, mass_op.apply(discr, ones)) true_integral = pi ** 2 err_1 = abs(num_integral_1 - true_integral) err_2 = abs(num_integral_2 - true_integral) # print err_1, err_2 assert err_1 < 1e-10 assert err_2 < 1e-10
def test_1d_mass_mat_trig(): """Check the integral of some trig functions on an interval using the mass matrix """ from hedge.mesh.generator import make_uniform_1d_mesh from hedge.discretization.local import IntervalDiscretization from math import pi, cos from numpy import dot mesh = make_uniform_1d_mesh(-4 * pi, 9 * pi, 17, periodic=True) discr = discr_class(mesh, IntervalDiscretization(8), debug=discr_class.noninteractive_debug_flags()) f = discr.interpolate_volume_function(lambda x, el: cos(x[0])**2) ones = discr.interpolate_volume_function(lambda x, el: 1) from hedge.optemplate import MassOperator mass_op = MassOperator() num_integral_1 = dot(ones, mass_op.apply(discr, f)) num_integral_2 = dot(f, mass_op.apply(discr, ones)) num_integral_3 = discr.integral(f) true_integral = 13 * pi / 2 err_1 = abs(num_integral_1 - true_integral) err_2 = abs(num_integral_2 - true_integral) err_3 = abs(num_integral_3 - true_integral) assert err_1 < 1e-10 assert err_2 < 1e-10 assert err_3 < 1e-10
def test_1d_mass_mat_trig(): """Check the integral of some trig functions on an interval using the mass matrix""" from hedge.mesh.generator import make_uniform_1d_mesh from hedge.discretization.local import IntervalDiscretization from math import sqrt, pi, cos, sin from numpy import dot mesh = make_uniform_1d_mesh(-4 * pi, 9 * pi, 17, periodic=True) discr = discr_class(mesh, IntervalDiscretization(8), debug=discr_class.noninteractive_debug_flags()) f = discr.interpolate_volume_function(lambda x, el: cos(x[0]) ** 2) ones = discr.interpolate_volume_function(lambda x, el: 1) from hedge.optemplate import MassOperator mass_op = MassOperator() num_integral_1 = dot(ones, mass_op.apply(discr, f)) num_integral_2 = dot(f, mass_op.apply(discr, ones)) num_integral_3 = discr.integral(f) true_integral = 13 * pi / 2 err_1 = abs(num_integral_1 - true_integral) err_2 = abs(num_integral_2 - true_integral) err_3 = abs(num_integral_3 - true_integral) assert err_1 < 1e-10 assert err_2 < 1e-10 assert err_3 < 1e-10
def test_tri_mass_mat_trig(): """Check the integral of some trig functions on a square using the mass matrix""" from hedge.mesh.generator import make_square_mesh from hedge.discretization.local import TriangleDiscretization from math import pi, cos, sin mesh = make_square_mesh(a=-pi, b=pi, max_area=(2 * pi / 10)**2 / 2) discr = discr_class(mesh, TriangleDiscretization(8), debug=discr_class.noninteractive_debug_flags()) f = discr.interpolate_volume_function( lambda x, el: cos(x[0])**2 * sin(x[1])**2) ones = discr.interpolate_volume_function(lambda x, el: 1) from hedge.optemplate import MassOperator mass_op = MassOperator() num_integral_1 = numpy.dot(ones, mass_op.apply(discr, f)) num_integral_2 = numpy.dot(f, mass_op.apply(discr, ones)) true_integral = pi**2 err_1 = abs(num_integral_1 - true_integral) err_2 = abs(num_integral_2 - true_integral) #print err_1, err_2 assert err_1 < 1e-10 assert err_2 < 1e-10
def test_tri_diff_mat(): """Check differentiation matrix along the coordinate axes on a disk Uses sines as the function to differentiate. """ from hedge.mesh.generator import make_disk_mesh from hedge.discretization.local import TriangleDiscretization from math import sin, cos, sqrt from hedge.optemplate import make_nabla nabla = make_nabla(2) for coord in [0, 1]: mesh = make_disk_mesh() discr = discr_class(make_disk_mesh(), TriangleDiscretization(4), debug=discr_class.noninteractive_debug_flags()) f = discr.interpolate_volume_function(lambda x, el: sin(3 * x[coord])) df = discr.interpolate_volume_function(lambda x, el: 3 * cos(3 * x[coord])) df_num = nabla[coord].apply(discr, f) # discr.visualize_vtk("diff-err.vtk", # [("f", f), ("df", df), ("df_num", df_num), ("error", error)]) linf_error = la.norm(df_num - df, numpy.Inf) print linf_error assert linf_error < 4e-5
def test_tri_diff_mat(): """Check differentiation matrix along the coordinate axes on a disk Uses sines as the function to differentiate. """ from hedge.mesh.generator import make_disk_mesh from hedge.discretization.local import TriangleDiscretization from math import sin, cos from hedge.optemplate import make_nabla nabla = make_nabla(2) for coord in [0, 1]: discr = discr_class(make_disk_mesh(), TriangleDiscretization(4), debug=discr_class.noninteractive_debug_flags()) f = discr.interpolate_volume_function(lambda x, el: sin(3 * x[coord])) df = discr.interpolate_volume_function( lambda x, el: 3 * cos(3 * x[coord])) df_num = nabla[coord].apply(discr, f) #discr.visualize_vtk("diff-err.vtk", #[("f", f), ("df", df), ("df_num", df_num), ("error", error)]) linf_error = la.norm(df_num - df, numpy.Inf) print linf_error assert linf_error < 4e-5
def test_quadrature_tri_mass_mat_monomial(): """Check that quadrature integration on triangles is exact as designed.""" from hedge.mesh.generator import make_square_mesh mesh = make_square_mesh(a=-1, b=1, max_area=4 * 1 / 8 + 0.001) order = 4 discr = discr_class( mesh, order=order, debug=discr_class.noninteractive_debug_flags(), quad_min_degrees={"quad": 3 * order} ) m, n = 2, 1 f = Monomial((m, n)) f_vec = discr.interpolate_volume_function(lambda x, el: f(x)) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test") vis.add_data(visf, [("f", f_vec * f_vec)]) visf.close() from hedge.optemplate import MassOperator, Field, QuadratureGridUpsampler f_fld = Field("f") mass_op = discr.compile(MassOperator()(f_fld * f_fld)) from hedge.optemplate.primitives import make_common_subexpression as cse f_upsamp = cse(QuadratureGridUpsampler("quad")(f_fld)) quad_mass_op = discr.compile(MassOperator()(f_upsamp * f_upsamp)) num_integral_1 = numpy.dot(ones, mass_op(f=f_vec)) num_integral_2 = numpy.dot(ones, quad_mass_op(f=f_vec)) true_integral = 4 / ((2 * m + 1) * (2 * n + 1)) err_1 = abs(num_integral_1 - true_integral) err_2 = abs(num_integral_2 - true_integral) print num_integral_1, num_integral_2, true_integral print err_1, err_2 assert err_1 > 1e-8 assert err_2 < 1e-14
def test_filter(): """Exercise mode-based filtering.""" from hedge.mesh.generator import make_disk_mesh from hedge.discretization.local import TriangleDiscretization from math import sin mesh = make_disk_mesh(r=3.4, max_area=0.5) discr = discr_class(mesh, TriangleDiscretization(5), debug=discr_class.noninteractive_debug_flags()) from hedge.optemplate.operators import FilterOperator from hedge.discretization import ExponentialFilterResponseFunction half_filter = FilterOperator(lambda mid, ldis: 0.5) for eg in discr.element_groups: fmat = half_filter.matrix(eg) n, m = fmat.shape assert la.norm(fmat - 0.5 * numpy.eye(n, m)) < 2e-15 from numpy import dot def test_freq(n): a = numpy.array([1, n]) def u_analytic(x, el): return sin(dot(a, x)) exp_filter = FilterOperator(ExponentialFilterResponseFunction(0.9, 3)) \ .bind(discr) u = discr.interpolate_volume_function(u_analytic) filt_u = exp_filter(u) int_error = abs(discr.integral(u) - discr.integral(filt_u)) l2_ratio = discr.norm(filt_u) / discr.norm(u) assert int_error < 1e-14 assert 0.96 < l2_ratio < 0.99999 test_freq(3) test_freq(5) test_freq(9) test_freq(17)
def test_quadrature_tri_mass_mat_monomial(): """Check that quadrature integration on triangles is exact as designed.""" from hedge.mesh.generator import make_square_mesh mesh = make_square_mesh(a=-1, b=1, max_area=4 * 1 / 8 + 0.001) order = 4 discr = discr_class(mesh, order=order, debug=discr_class.noninteractive_debug_flags(), quad_min_degrees={"quad": 3 * order}) m, n = 2, 1 f = Monomial((m, n)) f_vec = discr.interpolate_volume_function(lambda x, el: f(x)) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test") vis.add_data(visf, [("f", f_vec * f_vec)]) visf.close() from hedge.optemplate import (MassOperator, Field, QuadratureGridUpsampler) f_fld = Field("f") mass_op = discr.compile(MassOperator()(f_fld * f_fld)) from hedge.optemplate.primitives import make_common_subexpression as cse f_upsamp = cse(QuadratureGridUpsampler("quad")(f_fld)) quad_mass_op = discr.compile(MassOperator()(f_upsamp * f_upsamp)) num_integral_1 = numpy.dot(ones, mass_op(f=f_vec)) num_integral_2 = numpy.dot(ones, quad_mass_op(f=f_vec)) true_integral = 4 / ((2 * m + 1) * (2 * n + 1)) err_1 = abs(num_integral_1 - true_integral) err_2 = abs(num_integral_2 - true_integral) print num_integral_1, num_integral_2, true_integral print err_1, err_2 assert err_1 > 1e-8 assert err_2 < 1e-14
def test_filter(): """Exercise mode-based filtering.""" from hedge.mesh.generator import make_disk_mesh from hedge.discretization.local import TriangleDiscretization from math import sin mesh = make_disk_mesh(r=3.4, max_area=0.5) discr = discr_class(mesh, TriangleDiscretization(5), debug=discr_class.noninteractive_debug_flags()) from hedge.optemplate.operators import FilterOperator from hedge.discretization import ExponentialFilterResponseFunction half_filter = FilterOperator(lambda mid, ldis: 0.5) for eg in discr.element_groups: fmat = half_filter.matrix(eg) n, m = fmat.shape assert la.norm(fmat - 0.5*numpy.eye(n, m)) < 2e-15 from numpy import dot def test_freq(n): a = numpy.array([1, n]) def u_analytic(x, el): return sin(dot(a, x)) exp_filter = FilterOperator(ExponentialFilterResponseFunction(0.9, 3)) \ .bind(discr) u = discr.interpolate_volume_function(u_analytic) filt_u = exp_filter(u) int_error = abs(discr.integral(u) - discr.integral(filt_u)) l2_ratio = discr.norm(filt_u) / discr.norm(u) assert int_error < 1e-14 assert 0.96 < l2_ratio < 0.99999 test_freq(3) test_freq(5) test_freq(9) test_freq(17)
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 test_interior_fluxes_tet(): """Check tetrahedron surface integrals computed using interior fluxes against their known values. """ import meshpy.tet as tet from math import pi, sin, cos mesh_info = tet.MeshInfo() # construct a two-box extrusion of this base base = [(-pi, -pi, 0), (pi, -pi, 0), (pi, pi, 0), (-pi, pi, 0)] # first, the nodes mesh_info.set_points(base + [(x, y, z + pi) for x, y, z in base] + [(x, y, z + pi + 1) for x, y, z in base]) # next, the facets # vertex indices for a box missing the -z face box_without_minus_z = [ [4, 5, 6, 7], [0, 4, 5, 1], [1, 5, 6, 2], [2, 6, 7, 3], [3, 7, 4, 0], ] def add_to_all_vertex_indices(facets, increment): return [[pt + increment for pt in facet] for facet in facets] mesh_info.set_facets( [[0, 1, 2, 3]] # base + box_without_minus_z # first box + add_to_all_vertex_indices(box_without_minus_z, 4) # second box ) # set the volume properties -- this is where the tet size constraints are mesh_info.regions.resize(2) mesh_info.regions[0] = [ 0, 0, pi / 2, # point in volume -> first box 0, # region tag (user-defined number) 0.5, # max tet volume in region ] mesh_info.regions[1] = [ 0, 0, pi + 0.5, # point in volume -> second box 1, # region tag (user-defined number, arbitrary) 0.1, # max tet volume in region ] generated_mesh = tet.build(mesh_info, attributes=True, volume_constraints=True) from hedge.mesh import make_conformal_mesh mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements) from hedge.discretization.local import TetrahedronDiscretization from hedge.discretization import ones_on_volume discr = discr_class(mesh, TetrahedronDiscretization(4), debug=discr_class.noninteractive_debug_flags()) def f_u(x, el): if generated_mesh.element_attributes[el.id] == 1: return cos(x[0] - x[1] + x[2]) else: return 0 def f_l(x, el): if generated_mesh.element_attributes[el.id] == 0: return sin(x[0] - x[1] + x[2]) else: return 0 u_l = discr.interpolate_volume_function(f_l) u_u = discr.interpolate_volume_function(f_u) u = u_l + u_u # visualize the produced field #from hedge.visualization import SiloVisualizer #vis = SiloVisualizer(discr) #visf = vis.make_file("sandwich") #vis.add_data(visf, #[("u_l", u_l), ("u_u", u_u)], #expressions=[("u", "u_l+u_u")]) # make sure the surface integral of the difference # between top and bottom is zero from hedge.flux import make_normal, FluxScalarPlaceholder from hedge.optemplate import Field, get_flux_operator fluxu = FluxScalarPlaceholder() res = discr.compile( get_flux_operator( (fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) * Field("u"))(u=u) ones = ones_on_volume(discr) assert abs(numpy.dot(res, ones)) < 5e-14
def test_interior_fluxes_tri(): """Check triangle surface integrals computed using interior fluxes against their known values. """ from math import pi, sin, cos def round_trip_connect(start, end): for i in range(start, end): yield i, i + 1 yield end, start a = -pi b = pi points = [(a, 0), (b, 0), (a, -1), (b, -1), (a, 1), (b, 1)] import meshpy.triangle as triangle mesh_info = triangle.MeshInfo() mesh_info.set_points(points) mesh_info.set_facets([(0, 1), (1, 3), (3, 2), (2, 0), (0, 4), (4, 5), (1, 5)]) mesh_info.regions.resize(2) mesh_info.regions[0] = [ 0, -0.5, # coordinate 1, # lower element tag 0.1, # max area ] mesh_info.regions[1] = [ 0, 0.5, # coordinate 2, # upper element tag 0.01, # max area ] generated_mesh = triangle.build(mesh_info, attributes=True, volume_constraints=True) #triangle.write_gnuplot_mesh("mesh.dat", generated_mesh) def element_tagger(el): if generated_mesh.element_attributes[el.id] == 1: return ["upper"] else: return ["lower"] from hedge.mesh import make_conformal_mesh mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements) from hedge.discretization.local import TriangleDiscretization from hedge.discretization import ones_on_volume discr = discr_class(mesh, TriangleDiscretization(4), debug=discr_class.noninteractive_debug_flags()) def f_u(x, el): if generated_mesh.element_attributes[el.id] == 1: return cos(x[0] - x[1]) else: return 0 def f_l(x, el): if generated_mesh.element_attributes[el.id] == 0: return sin(x[0] - x[1]) else: return 0 # u_l = discr.interpolate_volume_function(f_l) u_u = discr.interpolate_volume_function(f_u) u = u_u + u_u #discr.visualize_vtk("dual.vtk", [("u", u)]) from hedge.flux import make_normal, FluxScalarPlaceholder from hedge.optemplate import Field, get_flux_operator fluxu = FluxScalarPlaceholder() res = discr.compile( get_flux_operator( (fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) * Field("u"))(u=u) ones = ones_on_volume(discr) err = abs(numpy.dot(res, ones)) #print err assert err < 5e-14
def test_2d_gauss_theorem(): """Verify Gauss's theorem explicitly on a mesh""" from hedge.mesh.generator import make_disk_mesh from math import sin, cos, sqrt, exp, pi from numpy import dot mesh = make_disk_mesh() order = 2 discr = discr_class(mesh, order=order, debug=discr_class.noninteractive_debug_flags()) ref_discr = discr_class(mesh, order=order) from hedge.flux import make_normal, FluxScalarPlaceholder normal = make_normal(discr.dimensions) flux_f_ph = FluxScalarPlaceholder(0) one_sided_x = flux_f_ph.int * normal[0] one_sided_y = flux_f_ph.int * normal[1] def f1(x, el): return sin(3 * x[0]) + cos(3 * x[1]) def f2(x, el): return sin(2 * x[0]) + cos(x[1]) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) f1_v = discr.interpolate_volume_function(f1) f2_v = discr.interpolate_volume_function(f2) from hedge.optemplate import BoundaryPair, Field, make_nabla, get_flux_operator nabla = make_nabla(discr.dimensions) diff_optp = nabla[0] * Field("f1") + nabla[1] * Field("f2") divergence = nabla[0].apply(discr, f1_v) + nabla[1].apply(discr, f2_v) int_div = discr.integral(divergence) flux_optp = get_flux_operator(one_sided_x)(BoundaryPair(Field("f1"), Field("fz"))) + get_flux_operator(one_sided_y)( BoundaryPair(Field("f2"), Field("fz")) ) from hedge.mesh import TAG_ALL bdry_val = discr.compile(flux_optp)(f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) ref_bdry_val = ref_discr.compile(flux_optp)(f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) boundary_int = dot(bdry_val, ones) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test") from hedge.tools import make_obj_array from hedge.mesh import TAG_ALL vis.add_data( visf, [ ("bdry", bdry_val), ("ref_bdry", ref_bdry_val), ("div", divergence), ("f", make_obj_array([f1_v, f2_v])), ("n", discr.volumize_boundary_field(discr.boundary_normals(TAG_ALL), TAG_ALL)), ], expressions=[("bdiff", "bdry-ref_bdry")], ) # print abs(boundary_int-int_div) assert abs(boundary_int - int_div) < 5e-15
def test_interior_fluxes_tri(): """Check triangle surface integrals computed using interior fluxes against their known values. """ from math import pi, sin, cos def round_trip_connect(start, end): for i in range(start, end): yield i, i + 1 yield end, start a = -pi b = pi points = [(a, 0), (b, 0), (a, -1), (b, -1), (a, 1), (b, 1)] import meshpy.triangle as triangle mesh_info = triangle.MeshInfo() mesh_info.set_points(points) mesh_info.set_facets([(0, 1), (1, 3), (3, 2), (2, 0), (0, 4), (4, 5), (1, 5)]) mesh_info.regions.resize(2) mesh_info.regions[0] = [0, -0.5, 1, 0.1] # coordinate # lower element tag # max area mesh_info.regions[1] = [0, 0.5, 2, 0.01] # coordinate # upper element tag # max area generated_mesh = triangle.build(mesh_info, attributes=True, volume_constraints=True) # triangle.write_gnuplot_mesh("mesh.dat", generated_mesh) def element_tagger(el): if generated_mesh.element_attributes[el.id] == 1: return ["upper"] else: return ["lower"] from hedge.mesh import make_conformal_mesh mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements) from hedge.discretization.local import TriangleDiscretization from hedge.discretization import ones_on_volume discr = discr_class(mesh, TriangleDiscretization(4), debug=discr_class.noninteractive_debug_flags()) def f_u(x, el): if generated_mesh.element_attributes[el.id] == 1: return cos(x[0] - x[1]) else: return 0 def f_l(x, el): if generated_mesh.element_attributes[el.id] == 0: return sin(x[0] - x[1]) else: return 0 u_l = discr.interpolate_volume_function(f_l) u_u = discr.interpolate_volume_function(f_u) u = u_u + u_u # discr.visualize_vtk("dual.vtk", [("u", u)]) from hedge.flux import make_normal, FluxScalarPlaceholder from hedge.optemplate import Field, get_flux_operator fluxu = FluxScalarPlaceholder() res = discr.compile(get_flux_operator((fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) * Field("u"))(u=u) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) err = abs(numpy.dot(res, ones)) # print err assert err < 5e-14
def test_2d_gauss_theorem(): """Verify Gauss's theorem explicitly on a mesh""" from hedge.mesh.generator import make_disk_mesh from math import sin, cos from numpy import dot mesh = make_disk_mesh() order = 2 discr = discr_class(mesh, order=order, debug=discr_class.noninteractive_debug_flags()) ref_discr = discr_class(mesh, order=order) from hedge.flux import make_normal, FluxScalarPlaceholder normal = make_normal(discr.dimensions) flux_f_ph = FluxScalarPlaceholder(0) one_sided_x = flux_f_ph.int * normal[0] one_sided_y = flux_f_ph.int * normal[1] def f1(x, el): return sin(3 * x[0]) + cos(3 * x[1]) def f2(x, el): return sin(2 * x[0]) + cos(x[1]) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) f1_v = discr.interpolate_volume_function(f1) f2_v = discr.interpolate_volume_function(f2) from hedge.optemplate import BoundaryPair, Field, make_nabla, \ get_flux_operator nabla = make_nabla(discr.dimensions) divergence = nabla[0].apply(discr, f1_v) + nabla[1].apply(discr, f2_v) int_div = discr.integral(divergence) flux_optp = ( get_flux_operator(one_sided_x)(BoundaryPair(Field("f1"), Field("fz"))) + get_flux_operator(one_sided_y)(BoundaryPair(Field("f2"), Field("fz")))) from hedge.mesh import TAG_ALL bdry_val = discr.compile(flux_optp)(f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) ref_bdry_val = ref_discr.compile(flux_optp)( f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) boundary_int = dot(bdry_val, ones) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test") from hedge.tools import make_obj_array from hedge.mesh import TAG_ALL vis.add_data(visf, [ ("bdry", bdry_val), ("ref_bdry", ref_bdry_val), ("div", divergence), ("f", make_obj_array([f1_v, f2_v])), ("n", discr.volumize_boundary_field(discr.boundary_normals(TAG_ALL), TAG_ALL)), ], expressions=[("bdiff", "bdry-ref_bdry")]) #print abs(boundary_int-int_div) assert abs(boundary_int - int_div) < 5e-15
def test_interior_fluxes_tet(): """Check tetrahedron surface integrals computed using interior fluxes against their known values. """ import meshpy.tet as tet from math import pi, sin, cos mesh_info = tet.MeshInfo() # construct a two-box extrusion of this base base = [(-pi, -pi, 0), (pi, -pi, 0), (pi, pi, 0), (-pi, pi, 0)] # first, the nodes mesh_info.set_points(base + [(x, y, z + pi) for x, y, z in base] + [(x, y, z + pi + 1) for x, y, z in base]) # next, the facets # vertex indices for a box missing the -z face box_without_minus_z = [[4, 5, 6, 7], [0, 4, 5, 1], [1, 5, 6, 2], [2, 6, 7, 3], [3, 7, 4, 0]] def add_to_all_vertex_indices(facets, increment): return [[pt + increment for pt in facet] for facet in facets] mesh_info.set_facets( [[0, 1, 2, 3]] # base + box_without_minus_z # first box + add_to_all_vertex_indices(box_without_minus_z, 4) # second box ) # set the volume properties -- this is where the tet size constraints are mesh_info.regions.resize(2) mesh_info.regions[0] = [ 0, 0, pi / 2, # point in volume -> first box 0, # region tag (user-defined number) 0.5, # max tet volume in region ] mesh_info.regions[1] = [ 0, 0, pi + 0.5, # point in volume -> second box 1, # region tag (user-defined number, arbitrary) 0.1, # max tet volume in region ] generated_mesh = tet.build(mesh_info, attributes=True, volume_constraints=True) from hedge.mesh import make_conformal_mesh mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements) from hedge.discretization.local import TetrahedronDiscretization from hedge.discretization import ones_on_volume discr = discr_class(mesh, TetrahedronDiscretization(4), debug=discr_class.noninteractive_debug_flags()) def f_u(x, el): if generated_mesh.element_attributes[el.id] == 1: return cos(x[0] - x[1] + x[2]) else: return 0 def f_l(x, el): if generated_mesh.element_attributes[el.id] == 0: return sin(x[0] - x[1] + x[2]) else: return 0 u_l = discr.interpolate_volume_function(f_l) u_u = discr.interpolate_volume_function(f_u) u = u_l + u_u # visualize the produced field # from hedge.visualization import SiloVisualizer # vis = SiloVisualizer(discr) # visf = vis.make_file("sandwich") # vis.add_data(visf, # [("u_l", u_l), ("u_u", u_u)], # expressions=[("u", "u_l+u_u")]) # make sure the surface integral of the difference # between top and bottom is zero from hedge.flux import make_normal, FluxScalarPlaceholder from hedge.optemplate import Field, get_flux_operator fluxu = FluxScalarPlaceholder() res = discr.compile(get_flux_operator((fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) * Field("u"))(u=u) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) assert abs(numpy.dot(res, ones)) < 5e-14
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