def test_nodal_dg_interop(actx_factory, dim): pytest.importorskip("oct2py") actx = actx_factory() download_nodal_dg_if_not_present() order = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, n=(8, ) * dim, order=order) from meshmode.interop.nodal_dg import NodalDGContext with NodalDGContext("./nodal-dg/Codes1.1") as ndgctx: ndgctx.set_mesh(mesh, order=order) discr = ndgctx.get_discr(actx) for ax in range(dim): x_ax = ndgctx.pull_dof_array(actx, ndgctx.AXES[ax]) err = flat_norm(x_ax - discr.nodes()[ax], np.inf) assert err < 1e-15 n0 = thaw(actx, discr.nodes()[0]) ndgctx.push_dof_array("n0", n0) n0_2 = ndgctx.pull_dof_array(actx, "n0") assert flat_norm(n0 - n0_2, np.inf) < 1e-15
def test_chained_connection(ctx_factory, ndim, visualize=False): ctx = ctx_factory() queue = cl.CommandQueue(ctx) actx = PyOpenCLArrayContext(queue) discr = create_discretization(actx, ndim, nelements=10) connections = [] conn = create_refined_connection(actx, discr, threshold=np.inf) connections.append(conn) conn = create_refined_connection(actx, conn.to_discr, threshold=np.inf) connections.append(conn) from meshmode.discretization.connection import \ ChainedDiscretizationConnection chained = ChainedDiscretizationConnection(connections) def f(x): from functools import reduce return 0.1 * reduce(lambda x, y: x * actx.np.sin(5 * y), x) x = thaw(actx, connections[0].from_discr.nodes()) fx = f(x) f1 = chained(fx) f2 = connections[1](connections[0](fx)) assert flat_norm(f1-f2, np.inf) / flat_norm(f2) < 1e-11
def main(): logging.basicConfig(level=logging.INFO) cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) nel_1d = 16 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, -0.5), b=(0.5, 0.5), nelements_per_axis=(nel_1d, nel_1d)) order = 3 # no deep meaning here, just a fudge factor dt = 0.7 / (nel_1d * order**2) logger.info("%d elements", mesh.nelements) discr = DGDiscretization(actx, mesh, order=order) fields = WaveState( u=bump(actx, discr), v=make_obj_array([discr.zeros(actx) for i in range(discr.dim)]), ) from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(actx, discr.volume_discr) def rhs(t, q): return wave_operator(actx, discr, c=1, q=q) t = 0 t_final = 3 istep = 0 while t < t_final: fields = rk4_step(fields, t, dt, rhs) if istep % 10 == 0: # FIXME: Maybe an integral function to go with the # DOFArray would be nice? assert len(fields.u) == 1 logger.info("[%05d] t %.5e / %.5e norm %.5e", istep, t, t_final, flat_norm(fields.u, 2)) vis.write_vtk_file("fld-wave-min-%04d.vtu" % istep, [ ("q", fields), ]) t += dt istep += 1 assert flat_norm(fields.u, 2) < 100
def test_mean_curvature(ctx_factory, discr_name, resolutions, discr_and_ref_mean_curvature_getter, visualize=False): ctx = ctx_factory() queue = cl.CommandQueue(ctx) actx = PyOpenCLArrayContext(queue) from pytools.convergence import EOCRecorder eoc = EOCRecorder() for r in resolutions: discr, ref_mean_curvature = \ discr_and_ref_mean_curvature_getter(actx, r) mean_curvature = bind(discr, sym.mean_curvature(discr.ambient_dim))(actx) h = 1.0 / r from meshmode.dof_array import flat_norm h_error = flat_norm(mean_curvature - ref_mean_curvature, np.inf) eoc.add_data_point(h, h_error) print(eoc) order = min([g.order for g in discr.groups]) assert eoc.order_estimate() > order - 1.1
def test_inverse_metric(actx_factory, dim): actx = actx_factory() mesh = mgen.generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, nelements_per_axis=(6, ) * dim, order=4) def m(x): result = np.empty_like(x) result[0] = (1.5 * x[0] + np.cos(x[0]) + 0.1 * np.sin(10 * x[1])) result[1] = (0.05 * np.cos(10 * x[0]) + 1.3 * x[1] + np.sin(x[1])) if len(x) == 3: result[2] = x[2] return result from meshmode.mesh.processing import map_mesh mesh = map_mesh(mesh, m) dcoll = DiscretizationCollection(actx, mesh, order=4) from grudge.geometry import \ forward_metric_derivative_mat, inverse_metric_derivative_mat mat = forward_metric_derivative_mat(actx, dcoll).dot( inverse_metric_derivative_mat(actx, dcoll)) for i in range(mesh.dim): for j in range(mesh.dim): tgt = 1 if i == j else 0 err = flat_norm(mat[i, j] - tgt, ord=np.inf) logger.info("error[%d, %d]: %.5e", i, j, err) assert err < 1.0e-12, (i, j, err)
def simple_mpi_communication_entrypoint(): cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue, force_device_scalars=True) from meshmode.distributed import MPIMeshDistributor, get_partition_by_pymetis from meshmode.mesh import BTAG_ALL from mpi4py import MPI comm = MPI.COMM_WORLD num_parts = comm.Get_size() mesh_dist = MPIMeshDistributor(comm) if mesh_dist.is_mananger_rank(): from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-1,)*2, b=(1,)*2, nelements_per_axis=(2,)*2) part_per_element = get_partition_by_pymetis(mesh, num_parts) local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element, num_parts) else: local_mesh = mesh_dist.receive_mesh_part() dcoll = DiscretizationCollection(actx, local_mesh, order=5, mpi_communicator=comm) x = thaw(dcoll.nodes(), actx) myfunc = actx.np.sin(np.dot(x, [2, 3])) from grudge.dof_desc import as_dofdesc dd_int = as_dofdesc("int_faces") dd_vol = as_dofdesc("vol") dd_af = as_dofdesc("all_faces") all_faces_func = op.project(dcoll, dd_vol, dd_af, myfunc) int_faces_func = op.project(dcoll, dd_vol, dd_int, myfunc) bdry_faces_func = op.project(dcoll, BTAG_ALL, dd_af, op.project(dcoll, dd_vol, BTAG_ALL, myfunc)) hopefully_zero = ( op.project( dcoll, "int_faces", "all_faces", dcoll.opposite_face_connection()(int_faces_func) ) + sum(op.project(dcoll, tpair.dd, "all_faces", tpair.int) for tpair in op.cross_rank_trace_pairs(dcoll, myfunc)) ) - (all_faces_func - bdry_faces_func) error = actx.to_numpy(flat_norm(hopefully_zero, ord=np.inf)) print(__file__) with np.printoptions(threshold=100000000, suppress=True): logger.debug(hopefully_zero) logger.info("error: %.5e", error) assert error < 1e-14
def test_flatten_unflatten(actx_factory): actx = actx_factory() ambient_dim = 2 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * ambient_dim, b=(+0.5, ) * ambient_dim, n=(3, ) * ambient_dim, order=1) discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(3)) a = np.random.randn(discr.ndofs) from meshmode.dof_array import flatten, unflatten a_round_trip = actx.to_numpy( flatten(unflatten(actx, discr, actx.from_numpy(a)))) assert np.array_equal(a, a_round_trip) from meshmode.dof_array import flatten_to_numpy, unflatten_from_numpy a_round_trip = flatten_to_numpy(actx, unflatten_from_numpy(actx, discr, a)) assert np.array_equal(a, a_round_trip) x = thaw(discr.nodes(), actx) avg_mass = DOFArray( actx, tuple([(np.pi + actx.zeros((grp.nelements, 1), a.dtype)) for grp in discr.groups])) c = MyContainer(name="flatten", mass=avg_mass, momentum=make_obj_array([x, x, x]), enthalpy=x) from meshmode.dof_array import unflatten_like c_round_trip = unflatten_like(actx, flatten(c), c) assert flat_norm(c - c_round_trip) < 1.0e-8
def simple_mpi_communication_entrypoint(): cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) from meshmode.distributed import MPIMeshDistributor, get_partition_by_pymetis from mpi4py import MPI comm = MPI.COMM_WORLD num_parts = comm.Get_size() mesh_dist = MPIMeshDistributor(comm) if mesh_dist.is_mananger_rank(): from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-1, ) * 2, b=(1, ) * 2, n=(3, ) * 2) part_per_element = get_partition_by_pymetis(mesh, num_parts) local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element, num_parts) else: local_mesh = mesh_dist.receive_mesh_part() vol_discr = DGDiscretizationWithBoundaries(actx, local_mesh, order=5, mpi_communicator=comm) sym_x = sym.nodes(local_mesh.dim) myfunc_symb = sym.sin(np.dot(sym_x, [2, 3])) myfunc = bind(vol_discr, myfunc_symb)(actx) sym_all_faces_func = sym.cse( sym.project("vol", "all_faces")(sym.var("myfunc"))) sym_int_faces_func = sym.cse( sym.project("vol", "int_faces")(sym.var("myfunc"))) sym_bdry_faces_func = sym.cse( sym.project(sym.BTAG_ALL, "all_faces")(sym.project("vol", sym.BTAG_ALL)(sym.var("myfunc")))) bound_face_swap = bind( vol_discr, sym.project("int_faces", "all_faces")( sym.OppositeInteriorFaceSwap("int_faces")(sym_int_faces_func)) - (sym_all_faces_func - sym_bdry_faces_func)) hopefully_zero = bound_face_swap(myfunc=myfunc) error = flat_norm(hopefully_zero, np.inf) print(__file__) with np.printoptions(threshold=100000000, suppress=True): logger.debug(hopefully_zero) logger.info("error: %.5e", error) assert error < 1e-14
def test_elementwise_reductions(actx_factory): actx = actx_factory() from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=1) nelements = 4 mesh = builder.get_mesh(nelements, builder.mesh_order) dcoll = DiscretizationCollection(actx, mesh, order=builder.order) x = thaw(dcoll.nodes(), actx) def f(x): return actx.np.sin(x[0]) field = f(x) mins = [] maxs = [] sums = [] for gidx, grp_f in enumerate(field): min_res = np.empty(grp_f.shape) max_res = np.empty(grp_f.shape) sum_res = np.empty(grp_f.shape) for eidx in range(dcoll._volume_discr.groups[gidx].nelements): element_data = actx.to_numpy(grp_f[eidx]) min_res[eidx, :] = np.min(element_data) max_res[eidx, :] = np.max(element_data) sum_res[eidx, :] = np.sum(element_data) mins.append(actx.from_numpy(min_res)) maxs.append(actx.from_numpy(max_res)) sums.append(actx.from_numpy(sum_res)) from meshmode.dof_array import DOFArray, flat_norm ref_mins = DOFArray(actx, data=tuple(mins)) ref_maxs = DOFArray(actx, data=tuple(maxs)) ref_sums = DOFArray(actx, data=tuple(sums)) elem_mins = op.elementwise_min(dcoll, field) elem_maxs = op.elementwise_max(dcoll, field) elem_sums = op.elementwise_sum(dcoll, field) assert flat_norm(elem_mins - ref_mins, ord=np.inf) < 1.e-15 assert flat_norm(elem_maxs - ref_maxs, ord=np.inf) < 1.e-15 assert flat_norm(elem_sums - ref_sums, ord=np.inf) < 1.e-15
def test_modal_coefficients_by_projection(actx_factory, quad_group_factory): group_cls = SimplexElementGroup modal_group_factory = ModalSimplexGroupFactory actx = actx_factory() order = 10 m_order = 5 # Make a regular rectangle mesh mesh = mgen.generate_regular_rect_mesh(a=(0, 0), b=(5, 3), npoints_per_axis=(10, 6), order=order, group_cls=group_cls) # Make discretizations nodal_disc = Discretization(actx, mesh, quad_group_factory(order)) modal_disc = Discretization(actx, mesh, modal_group_factory(m_order)) # Make connections one using quadrature projection nodal_to_modal_conn_quad = NodalToModalDiscretizationConnection( nodal_disc, modal_disc, allow_approximate_quad=True) def f(x): return 2 * actx.np.sin(5 * x) x_nodal = thaw(nodal_disc.nodes()[0], actx) nodal_f = f(x_nodal) # Compute modal coefficients we expect to get import modepy as mp grp, = nodal_disc.groups shape = mp.Simplex(grp.dim) space = mp.space_for_shape(shape, order=m_order) basis = mp.orthonormal_basis_for_space(space, shape) quad = grp.quadrature_rule() nodal_f_data = actx.to_numpy(nodal_f[0]) vdm = mp.vandermonde(basis.functions, quad.nodes) w_diag = np.diag(quad.weights) modal_data = [] for _, nodal_data in enumerate(nodal_f_data): # Compute modal data in each element: V.T * W * nodal_data elem_modal_f = np.dot(vdm.T, np.dot(w_diag, nodal_data)) modal_data.append(elem_modal_f) modal_data = actx.from_numpy(np.asarray(modal_data)) modal_f_expected = DOFArray(actx, data=(modal_data, )) # Map nodal coefficients using the quadrature-based projection modal_f_computed = nodal_to_modal_conn_quad(nodal_f) err = flat_norm(modal_f_expected - modal_f_computed) assert err <= 1e-13
def run(nelements, order): discr = create_discretization(actx, ndim, nelements=nelements, order=order, mesh_name=mesh_name) threshold = 1.0 connections = [] conn = create_refined_connection(actx, discr, threshold=threshold) connections.append(conn) if ndim == 2: # NOTE: additional refinement makes the 3D meshes explode in size conn = create_refined_connection(actx, conn.to_discr, threshold=threshold) connections.append(conn) conn = create_refined_connection(actx, conn.to_discr, threshold=threshold) connections.append(conn) from meshmode.discretization.connection import \ ChainedDiscretizationConnection chained = ChainedDiscretizationConnection(connections) from meshmode.discretization.connection import \ L2ProjectionInverseDiscretizationConnection reverse = L2ProjectionInverseDiscretizationConnection(chained) # create test vector from_nodes = thaw(chained.from_discr.nodes(), actx) to_nodes = thaw(chained.to_discr.nodes(), actx) from_x = 0 to_x = 0 for d in range(ndim): from_x = from_x + actx.np.cos(from_nodes[d])**(d + 1) to_x = to_x + actx.np.cos(to_nodes[d])**(d + 1) from_interp = reverse(to_x) return (1.0 / nelements, flat_norm(from_interp - from_x, np.inf) / flat_norm(from_x, np.inf))
def test_sanity_qhull_nd(actx_factory, dim, order): pytest.importorskip("scipy") logging.basicConfig(level=logging.INFO) actx = actx_factory() from scipy.spatial import Delaunay # pylint: disable=no-name-in-module verts = np.random.rand(1000, dim) dtri = Delaunay(verts) # pylint: disable=no-member from meshmode.mesh.io import from_vertices_and_simplices mesh = from_vertices_and_simplices(dtri.points.T, dtri.simplices, fix_orientation=True) from meshmode.discretization import Discretization low_discr = Discretization(actx, mesh, PolynomialEquidistantSimplexGroupFactory(order)) high_discr = Discretization( actx, mesh, PolynomialEquidistantSimplexGroupFactory(order + 1)) from meshmode.discretization.connection import make_same_mesh_connection cnx = make_same_mesh_connection(actx, high_discr, low_discr) def f(x): return 0.1 * actx.np.sin(x) x_low = thaw(low_discr.nodes()[0], actx) f_low = f(x_low) x_high = thaw(high_discr.nodes()[0], actx) f_high_ref = f(x_high) f_high_num = cnx(f_low) err = (flat_norm(f_high_ref - f_high_num, np.inf) / flat_norm(f_high_ref, np.inf)) print(err) assert err < 1e-2
def test_container_norm(actx_factory, ord): actx = actx_factory() ary_dof, ary_of_dofs, mat_of_dofs, dc_of_dofs = _get_test_containers(actx) from pytools.obj_array import make_obj_array c = MyContainer(name="hey", mass=1, momentum=make_obj_array([2, 3]), enthalpy=5) n1 = actx.np.linalg.norm(make_obj_array([c, c]), ord) n2 = np.linalg.norm([1, 2, 3, 5] * 2, ord) assert abs(n1 - n2) < 1e-12 assert abs(flat_norm(ary_dof, ord) - actx.np.linalg.norm(ary_dof, ord)) < 1e-12
def test_inverse_modal_connections(actx_factory, nodal_group_factory): if nodal_group_factory is LegendreGaussLobattoTensorProductGroupFactory: group_cls = TensorProductElementGroup modal_group_factory = ModalTensorProductGroupFactory else: group_cls = SimplexElementGroup modal_group_factory = ModalSimplexGroupFactory actx = actx_factory() order = 4 def f(x): return 2 * actx.np.sin(20 * x) + 0.5 * actx.np.cos(10 * x) # Make a regular rectangle mesh mesh = mgen.generate_regular_rect_mesh(a=(0, 0), b=(5, 3), npoints_per_axis=(10, 6), order=order, group_cls=group_cls) # Make discretizations nodal_disc = Discretization(actx, mesh, nodal_group_factory(order)) modal_disc = Discretization(actx, mesh, modal_group_factory(order)) # Make connections nodal_to_modal_conn = NodalToModalDiscretizationConnection( nodal_disc, modal_disc) modal_to_nodal_conn = ModalToNodalDiscretizationConnection( modal_disc, nodal_disc) x_nodal = thaw(nodal_disc.nodes()[0], actx) nodal_f = f(x_nodal) # Map nodal coefficients of f to modal coefficients modal_f = nodal_to_modal_conn(nodal_f) # Now map the modal coefficients back to nodal nodal_f_2 = modal_to_nodal_conn(modal_f) # This error should be small since we composed a map with # its inverse err = flat_norm(nodal_f - nodal_f_2) assert err <= 1e-13
def test_inverse_modal_connections_quadgrid(actx_factory): actx = actx_factory() order = 5 def f(x): return 1 + 2 * x + 3 * x**2 # Make a regular rectangle mesh mesh = mgen.generate_regular_rect_mesh( a=(0, 0), b=(5, 3), npoints_per_axis=(10, 6), order=order, group_cls=QuadratureSimplexGroupFactory.mesh_group_class) dcoll = DiscretizationCollection( actx, mesh, discr_tag_to_group_factory={ dof_desc.DISCR_TAG_BASE: PolynomialWarpAndBlend2DRestrictingGroupFactory(order), dof_desc.DISCR_TAG_QUAD: QuadratureSimplexGroupFactory(2 * order) }) # Use dof descriptors on the quadrature grid dd_modal = dof_desc.DD_VOLUME_MODAL dd_quad = dof_desc.DOFDesc(dof_desc.DTAG_VOLUME_ALL, dof_desc.DISCR_TAG_QUAD) x_quad = thaw(dcoll.discr_from_dd(dd_quad).nodes()[0], actx) quad_f = f(x_quad) # Map nodal coefficients of f to modal coefficients forward_conn = dcoll.connection_from_dds(dd_quad, dd_modal) modal_f = forward_conn(quad_f) # Now map the modal coefficients back to nodal backward_conn = dcoll.connection_from_dds(dd_modal, dd_quad) quad_f_2 = backward_conn(modal_f) # This error should be small since we composed a map with # its inverse err = flat_norm(quad_f - quad_f_2) assert err <= 1e-11
def test_quadrature_based_modal_connection_reverse(actx_factory, quad_group_factory): group_cls = SimplexElementGroup modal_group_factory = ModalSimplexGroupFactory actx = actx_factory() order = 10 m_order = 5 # Make a regular rectangle mesh mesh = mgen.generate_regular_rect_mesh(a=(0, 0), b=(5, 3), npoints_per_axis=(10, 6), order=order, group_cls=group_cls) # Make discretizations nodal_disc = Discretization(actx, mesh, quad_group_factory(order)) modal_disc = Discretization(actx, mesh, modal_group_factory(m_order)) # Make connections one using quadrature projection nodal_to_modal_conn_quad = NodalToModalDiscretizationConnection( nodal_disc, modal_disc) # And the reverse connection modal_to_nodal_conn = ModalToNodalDiscretizationConnection( modal_disc, nodal_disc) def f(x): return 1 + 2 * x + 3 * x**2 x_nodal = thaw(nodal_disc.nodes()[0], actx) nodal_f = f(x_nodal) # Map nodal coefficients using the quadrature-based projection modal_f_quad = nodal_to_modal_conn_quad(nodal_f) # Back to nodal nodal_f_computed = modal_to_nodal_conn(modal_f_quad) err = flat_norm(nodal_f - nodal_f_computed) assert err <= 1e-11
def test_tri_diff_mat(ctx_factory, dim, order=4): """Check differentiation matrix along the coordinate axes on a disk Uses sines as the function to differentiate. """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) from meshmode.mesh.generation import generate_regular_rect_mesh from pytools.convergence import EOCRecorder axis_eoc_recs = [EOCRecorder() for axis in range(dim)] for n in [10, 20]: mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, n=(n, ) * dim, order=4) discr = DGDiscretizationWithBoundaries(actx, mesh, order=4) nabla = sym.nabla(dim) for axis in range(dim): x = sym.nodes(dim) f = bind(discr, sym.sin(3 * x[axis]))(actx) df = bind(discr, 3 * sym.cos(3 * x[axis]))(actx) sym_op = nabla[axis](sym.var("f")) bound_op = bind(discr, sym_op) df_num = bound_op(f=f) linf_error = flat_norm(df_num - df, np.Inf) axis_eoc_recs[axis].add_data_point(1 / n, linf_error) for axis, eoc_rec in enumerate(axis_eoc_recs): logger.info("axis %d\n%s", axis, eoc_rec) assert eoc_rec.order_estimate() >= order
def test_inverse_modal_connections(actx_factory, nodal_group_factory): actx = actx_factory() order = 4 def f(x): return 2 * actx.np.sin(20 * x) + 0.5 * actx.np.cos(10 * x) # Make a regular rectangle mesh mesh = mgen.generate_regular_rect_mesh( a=(0, 0), b=(5, 3), npoints_per_axis=(10, 6), order=order, group_cls=nodal_group_factory.mesh_group_class) dcoll = DiscretizationCollection(actx, mesh, discr_tag_to_group_factory={ dof_desc.DISCR_TAG_BASE: nodal_group_factory(order) }) dd_modal = dof_desc.DD_VOLUME_MODAL dd_volume = dof_desc.DD_VOLUME x_nodal = thaw(dcoll.discr_from_dd(dd_volume).nodes()[0], actx) nodal_f = f(x_nodal) # Map nodal coefficients of f to modal coefficients forward_conn = dcoll.connection_from_dds(dd_volume, dd_modal) modal_f = forward_conn(nodal_f) # Now map the modal coefficients back to nodal backward_conn = dcoll.connection_from_dds(dd_modal, dd_volume) nodal_f_2 = backward_conn(modal_f) # This error should be small since we composed a map with # its inverse err = flat_norm(nodal_f - nodal_f_2) assert err <= 1e-13
def test_tri_diff_mat(actx_factory, dim, order=4): """Check differentiation matrix along the coordinate axes on a disk Uses sines as the function to differentiate. """ actx = actx_factory() from pytools.convergence import EOCRecorder axis_eoc_recs = [EOCRecorder() for axis in range(dim)] def f(x, axis): return actx.np.sin(3 * x[axis]) def df(x, axis): return 3 * actx.np.cos(3 * x[axis]) for n in [4, 8, 16]: mesh = mgen.generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, nelements_per_axis=(n, ) * dim, order=4) dcoll = DiscretizationCollection(actx, mesh, order=4) volume_discr = dcoll.discr_from_dd(dof_desc.DD_VOLUME) x = thaw(volume_discr.nodes(), actx) for axis in range(dim): df_num = op.local_grad(dcoll, f(x, axis))[axis] df_volm = df(x, axis) linf_error = flat_norm(df_num - df_volm, ord=np.inf) axis_eoc_recs[axis].add_data_point(1 / n, actx.to_numpy(linf_error)) for axis, eoc_rec in enumerate(axis_eoc_recs): logger.info("axis %d\n%s", axis, eoc_rec) assert eoc_rec.order_estimate() > order - 0.25
def test_inverse_metric(ctx_factory, dim): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, n=(6, ) * dim, order=4) def m(x): result = np.empty_like(x) result[0] = (1.5 * x[0] + np.cos(x[0]) + 0.1 * np.sin(10 * x[1])) result[1] = (0.05 * np.cos(10 * x[0]) + 1.3 * x[1] + np.sin(x[1])) if len(x) == 3: result[2] = x[2] return result from meshmode.mesh.processing import map_mesh mesh = map_mesh(mesh, m) discr = DGDiscretizationWithBoundaries(actx, mesh, order=4) sym_op = (sym.forward_metric_derivative_mat(mesh.dim).dot( sym.inverse_metric_derivative_mat(mesh.dim)).reshape(-1)) op = bind(discr, sym_op) mat = op(actx).reshape(mesh.dim, mesh.dim) for i in range(mesh.dim): for j in range(mesh.dim): tgt = 1 if i == j else 0 err = flat_norm(mat[i, j] - tgt, np.inf) logger.info("error[%d, %d]: %.5e", i, j, err) assert err < 1.0e-12, (i, j, err)
def test_diffusion_compare_to_nodal_dg(actx_factory, problem, order, print_err=False): """Compares diffusion operator to Hesthaven/Warburton Nodal-DG code.""" pytest.importorskip("oct2py") actx = actx_factory() p = problem assert p.dim == 1 assert p.alpha == 1. from meshmode.interop.nodal_dg import download_nodal_dg_if_not_present download_nodal_dg_if_not_present() sym_diffusion_u = sym_diffusion(p.dim, p.alpha, p.sym_u) for n in [4, 8, 16, 32, 64]: mesh = p.get_mesh(n) from meshmode.interop.nodal_dg import NodalDGContext with NodalDGContext("./nodal-dg/Codes1.1") as ndgctx: ndgctx.set_mesh(mesh, order=order) t = 1.23456789 from grudge.eager import EagerDGDiscretization discr_mirgecom = EagerDGDiscretization(actx, mesh, order=order) nodes_mirgecom = thaw(actx, discr_mirgecom.nodes()) def sym_eval_mirgecom(expr): return sym.EvaluationMapper({ "x": nodes_mirgecom, "t": t })(expr) u_mirgecom = sym_eval_mirgecom(p.sym_u) diffusion_u_mirgecom = diffusion_operator( discr_mirgecom, alpha=p.alpha, boundaries=p.get_boundaries(discr_mirgecom, actx, t), u=u_mirgecom) discr_ndg = ndgctx.get_discr(actx) nodes_ndg = thaw(actx, discr_ndg.nodes()) def sym_eval_ndg(expr): return sym.EvaluationMapper({"x": nodes_ndg, "t": t})(expr) u_ndg = sym_eval_ndg(p.sym_u) ndgctx.push_dof_array("u", u_ndg) ndgctx.octave.push("t", t) ndgctx.octave.eval("[rhs] = HeatCRHS1D(u,t)", verbose=False) diffusion_u_ndg = ndgctx.pull_dof_array(actx, "rhs") err = (flat_norm(diffusion_u_mirgecom - diffusion_u_ndg, np.inf) / flat_norm(diffusion_u_ndg, np.inf)) if print_err: diffusion_u_exact = sym_eval_mirgecom(sym_diffusion_u) err_exact = (flat_norm( diffusion_u_mirgecom - diffusion_u_exact, np.inf) / flat_norm(diffusion_u_exact, np.inf)) print(err, err_exact) assert err < 1e-9
def test_partition_interpolation(ctx_factory, dim, mesh_pars, num_parts, num_groups, part_method): np.random.seed(42) group_factory = PolynomialWarpAndBlendGroupFactory cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) order = 4 def f(x): return 10.*actx.np.sin(50.*x) for n in mesh_pars: from meshmode.mesh.generation import generate_warped_rect_mesh base_mesh = generate_warped_rect_mesh(dim, order=order, n=n) if num_groups > 1: from meshmode.mesh.processing import split_mesh_groups # Group every Nth element element_flags = np.arange(base_mesh.nelements, dtype=base_mesh.element_id_dtype) % num_groups mesh = split_mesh_groups(base_mesh, element_flags) else: mesh = base_mesh if part_method == "random": part_per_element = np.random.randint(num_parts, size=mesh.nelements) else: pytest.importorskip('pymetis') from meshmode.distributed import get_partition_by_pymetis part_per_element = get_partition_by_pymetis(mesh, num_parts, connectivity=part_method) from meshmode.mesh.processing import partition_mesh part_meshes = [ partition_mesh(mesh, part_per_element, i)[0] for i in range(num_parts)] connected_parts = set() for i_local_part, part_mesh in enumerate(part_meshes): from meshmode.distributed import get_connected_partitions neighbors = get_connected_partitions(part_mesh) for i_remote_part in neighbors: connected_parts.add((i_local_part, i_remote_part)) from meshmode.discretization import Discretization vol_discrs = [Discretization(actx, part_meshes[i], group_factory(order)) for i in range(num_parts)] from meshmode.mesh import BTAG_PARTITION from meshmode.discretization.connection import (make_face_restriction, make_partition_connection, check_connection) for i_local_part, i_remote_part in connected_parts: # Mark faces within local_mesh that are connected to remote_mesh local_bdry_conn = make_face_restriction(actx, vol_discrs[i_local_part], group_factory(order), BTAG_PARTITION(i_remote_part)) # Mark faces within remote_mesh that are connected to local_mesh remote_bdry_conn = make_face_restriction(actx, vol_discrs[i_remote_part], group_factory(order), BTAG_PARTITION(i_local_part)) bdry_nelements = sum( grp.nelements for grp in local_bdry_conn.to_discr.groups) remote_bdry_nelements = sum( grp.nelements for grp in remote_bdry_conn.to_discr.groups) assert bdry_nelements == remote_bdry_nelements, \ "partitions do not have the same number of connected elements" # Gather just enough information for the connection local_bdry = local_bdry_conn.to_discr local_mesh = part_meshes[i_local_part] local_adj_groups = [local_mesh.facial_adjacency_groups[i][None] for i in range(len(local_mesh.groups))] local_batches = [local_bdry_conn.groups[i].batches for i in range(len(local_mesh.groups))] local_from_elem_faces = [[batch.to_element_face for batch in grp_batches] for grp_batches in local_batches] local_from_elem_indices = [[batch.to_element_indices.get(queue=queue) for batch in grp_batches] for grp_batches in local_batches] remote_bdry = remote_bdry_conn.to_discr remote_mesh = part_meshes[i_remote_part] remote_adj_groups = [remote_mesh.facial_adjacency_groups[i][None] for i in range(len(remote_mesh.groups))] remote_batches = [remote_bdry_conn.groups[i].batches for i in range(len(remote_mesh.groups))] remote_from_elem_faces = [[batch.to_element_face for batch in grp_batches] for grp_batches in remote_batches] remote_from_elem_indices = [[batch.to_element_indices.get(queue=queue) for batch in grp_batches] for grp_batches in remote_batches] # Connect from remote_mesh to local_mesh remote_to_local_conn = make_partition_connection( actx, local_bdry_conn, i_local_part, remote_bdry, remote_adj_groups, remote_from_elem_faces, remote_from_elem_indices) # Connect from local mesh to remote mesh local_to_remote_conn = make_partition_connection( actx, remote_bdry_conn, i_remote_part, local_bdry, local_adj_groups, local_from_elem_faces, local_from_elem_indices) check_connection(actx, remote_to_local_conn) check_connection(actx, local_to_remote_conn) true_local_points = f(thaw(actx, local_bdry.nodes()[0])) remote_points = local_to_remote_conn(true_local_points) local_points = remote_to_local_conn(remote_points) err = flat_norm(true_local_points - local_points, np.inf) # Can't currently expect exact results due to limitations of # interpolation 'snapping' in DirectDiscretizationConnection's # _resample_point_pick_indices assert err < 1e-11
def test_boundary_interpolation(actx_factory, group_factory, boundary_tag, mesh_name, dim, mesh_pars, per_face_groups): if (group_factory is LegendreGaussLobattoTensorProductGroupFactory and mesh_name == "blob"): pytest.skip("tensor products not implemented on blobs") actx = actx_factory() if group_factory is LegendreGaussLobattoTensorProductGroupFactory: group_cls = TensorProductElementGroup else: group_cls = SimplexElementGroup from meshmode.discretization import Discretization from meshmode.discretization.connection import (make_face_restriction, check_connection) from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() order = 4 def f(x): return 0.1 * actx.np.sin(30 * x) for mesh_par in mesh_pars: # {{{ get mesh if mesh_name == "blob": assert dim == 2 h = float(mesh_par) #from meshmode.mesh.io import generate_gmsh, FileSource # print("BEGIN GEN") # mesh = generate_gmsh( # FileSource("blob-2d.step"), 2, order=order, # force_ambient_dim=2, # other_options=[ # "-string", "Mesh.CharacteristicLengthMax = %s;" % h] # ) # print("END GEN") from meshmode.mesh.io import read_gmsh mesh = read_gmsh("blob2d-order%d-h%s.msh" % (order, mesh_par), force_ambient_dim=2) elif mesh_name == "warp": mesh = mgen.generate_warped_rect_mesh(dim, order=order, nelements_side=mesh_par, group_cls=group_cls) h = 1 / mesh_par elif mesh_name == "rect": mesh = mgen.generate_regular_rect_mesh( a=(0, ) * dim, b=(1, ) * dim, order=order, nelements_per_axis=(mesh_par, ) * dim, group_cls=group_cls) h = 1 / mesh_par else: raise ValueError("mesh_name not recognized") # }}} vol_discr = Discretization(actx, mesh, group_factory(order)) print("h=%s -> %d elements" % (h, sum(mgrp.nelements for mgrp in mesh.groups))) x = thaw(vol_discr.nodes()[0], actx) vol_f = f(x) bdry_connection = make_face_restriction( actx, vol_discr, group_factory(order), boundary_tag, per_face_groups=per_face_groups) check_connection(actx, bdry_connection) bdry_discr = bdry_connection.to_discr bdry_x = thaw(bdry_discr.nodes()[0], actx) bdry_f = f(bdry_x) bdry_f_2 = bdry_connection(vol_f) if mesh_name == "blob" and dim == 2 and mesh.nelements < 500: from meshmode.discretization.connection.direct import \ make_direct_full_resample_matrix mat = actx.to_numpy( make_direct_full_resample_matrix(actx, bdry_connection)) bdry_f_2_by_mat = mat.dot(flatten_to_numpy(actx, vol_f)) mat_error = la.norm( flatten_to_numpy(actx, bdry_f_2) - bdry_f_2_by_mat) assert mat_error < 1e-14, mat_error err = flat_norm(bdry_f - bdry_f_2, np.inf) eoc_rec.add_data_point(h, err) order_slack = 0.75 if mesh_name == "blob" else 0.5 print(eoc_rec) assert (eoc_rec.order_estimate() >= order - order_slack or eoc_rec.max_error() < 3.6e-13)
def test_mesh_multiple_groups(actx_factory, ambient_dim, visualize=False): actx = actx_factory() order = 4 mesh = mgen.generate_regular_rect_mesh(a=(-0.5, ) * ambient_dim, b=(0.5, ) * ambient_dim, nelements_per_axis=(8, ) * ambient_dim, order=order) assert len(mesh.groups) == 1 from meshmode.mesh.processing import split_mesh_groups element_flags = np.any( mesh.vertices[0, mesh.groups[0].vertex_indices] < 0.0, axis=1).astype(np.int64) mesh = split_mesh_groups(mesh, element_flags) assert len(mesh.groups) == 2 # pylint: disable=no-member assert mesh.facial_adjacency_groups assert mesh.nodal_adjacency if visualize and ambient_dim == 2: from meshmode.mesh.visualization import draw_2d_mesh draw_2d_mesh(mesh, draw_vertex_numbers=False, draw_element_numbers=True, draw_face_numbers=False, set_bounding_box=True) import matplotlib.pyplot as plt plt.savefig("test_mesh_multiple_groups_2d_elements.png", dpi=300) from meshmode.discretization import Discretization discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(order)) if visualize: group_id = discr.empty(actx, dtype=np.int32) for igrp, vec in enumerate(group_id): vec.fill(igrp) from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(actx, discr, vis_order=order) vis.write_vtk_file("mesh_multiple_groups.vtu", [("group_id", group_id)], overwrite=True) # check face restrictions from meshmode.discretization.connection import ( make_face_restriction, make_face_to_all_faces_embedding, make_opposite_face_connection, check_connection) for boundary_tag in [BTAG_ALL, FACE_RESTR_INTERIOR, FACE_RESTR_ALL]: conn = make_face_restriction( actx, discr, group_factory=PolynomialWarpAndBlendGroupFactory(order), boundary_tag=boundary_tag, per_face_groups=False) check_connection(actx, conn) bdry_f = conn.to_discr.zeros(actx) + 1 if boundary_tag == FACE_RESTR_INTERIOR: opposite = make_opposite_face_connection(actx, conn) check_connection(actx, opposite) op_bdry_f = opposite(bdry_f) error = flat_norm(bdry_f - op_bdry_f, np.inf) assert error < 1.0e-11, error if boundary_tag == FACE_RESTR_ALL: embedding = make_face_to_all_faces_embedding( actx, conn, conn.to_discr) check_connection(actx, embedding) em_bdry_f = embedding(bdry_f) error = flat_norm(bdry_f - em_bdry_f) assert error < 1.0e-11, error # check some derivatives (nb: flatten is a generator) import pytools ref_axes = pytools.flatten([[i] for i in range(ambient_dim)]) from meshmode.discretization import num_reference_derivative x = thaw(discr.nodes(), actx) num_reference_derivative(discr, ref_axes, x[0])
def test_partition_interpolation(actx_factory, dim, mesh_pars, num_parts, num_groups, part_method): np.random.seed(42) group_factory = PolynomialWarpAndBlendGroupFactory actx = actx_factory() order = 4 def f(x): return 10.*actx.np.sin(50.*x) for n in mesh_pars: from meshmode.mesh.generation import generate_warped_rect_mesh base_mesh = generate_warped_rect_mesh(dim, order=order, nelements_side=n) if num_groups > 1: from meshmode.mesh.processing import split_mesh_groups # Group every Nth element element_flags = np.arange(base_mesh.nelements, dtype=base_mesh.element_id_dtype) % num_groups mesh = split_mesh_groups(base_mesh, element_flags) else: mesh = base_mesh if part_method == "random": part_per_element = np.random.randint(num_parts, size=mesh.nelements) else: pytest.importorskip("pymetis") from meshmode.distributed import get_partition_by_pymetis part_per_element = get_partition_by_pymetis(mesh, num_parts, connectivity=part_method) from meshmode.mesh.processing import partition_mesh part_meshes = [ partition_mesh(mesh, part_per_element, i)[0] for i in range(num_parts)] connected_parts = set() for i_local_part, part_mesh in enumerate(part_meshes): from meshmode.distributed import get_connected_partitions neighbors = get_connected_partitions(part_mesh) for i_remote_part in neighbors: connected_parts.add((i_local_part, i_remote_part)) from meshmode.discretization import Discretization vol_discrs = [Discretization(actx, part_meshes[i], group_factory(order)) for i in range(num_parts)] from meshmode.mesh import BTAG_PARTITION from meshmode.discretization.connection import (make_face_restriction, make_partition_connection, check_connection) for i_local_part, i_remote_part in connected_parts: # Mark faces within local_mesh that are connected to remote_mesh local_bdry_conn = make_face_restriction(actx, vol_discrs[i_local_part], group_factory(order), BTAG_PARTITION(i_remote_part)) # Mark faces within remote_mesh that are connected to local_mesh remote_bdry_conn = make_face_restriction(actx, vol_discrs[i_remote_part], group_factory(order), BTAG_PARTITION(i_local_part)) bdry_nelements = sum( grp.nelements for grp in local_bdry_conn.to_discr.groups) remote_bdry_nelements = sum( grp.nelements for grp in remote_bdry_conn.to_discr.groups) assert bdry_nelements == remote_bdry_nelements, \ "partitions do not have the same number of connected elements" local_bdry = local_bdry_conn.to_discr remote_bdry = remote_bdry_conn.to_discr from meshmode.distributed import make_remote_group_infos remote_to_local_conn = make_partition_connection( actx, local_bdry_conn=local_bdry_conn, i_local_part=i_local_part, remote_bdry_discr=remote_bdry, remote_group_infos=make_remote_group_infos( actx, remote_bdry_conn)) # Connect from local mesh to remote mesh local_to_remote_conn = make_partition_connection( actx, local_bdry_conn=remote_bdry_conn, i_local_part=i_remote_part, remote_bdry_discr=local_bdry, remote_group_infos=make_remote_group_infos( actx, local_bdry_conn)) check_connection(actx, remote_to_local_conn) check_connection(actx, local_to_remote_conn) true_local_points = f(thaw(local_bdry.nodes()[0], actx)) remote_points = local_to_remote_conn(true_local_points) local_points = remote_to_local_conn(remote_points) err = flat_norm(true_local_points - local_points, np.inf) # Can't currently expect exact results due to limitations of # interpolation "snapping" in DirectDiscretizationConnection's # _resample_point_pick_indices assert err < 1e-11
def test_opposite_face_interpolation(actx_factory, group_factory, mesh_name, dim, mesh_pars): if (group_factory is LegendreGaussLobattoTensorProductGroupFactory and mesh_name in ["segment", "blob"]): pytest.skip("tensor products not implemented on blobs") logging.basicConfig(level=logging.INFO) actx = actx_factory() if group_factory is LegendreGaussLobattoTensorProductGroupFactory: group_cls = TensorProductElementGroup else: group_cls = SimplexElementGroup from meshmode.discretization import Discretization from meshmode.discretization.connection import ( make_face_restriction, make_opposite_face_connection, check_connection) from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() order = 5 def f(x): return 0.1 * actx.np.sin(30 * x) for mesh_par in mesh_pars: # {{{ get mesh if mesh_name == "segment": assert dim == 1 mesh = mgen.generate_box_mesh([np.linspace(-0.5, 0.5, mesh_par)], order=order, group_cls=group_cls) h = 1.0 / mesh_par elif mesh_name == "blob": assert dim == 2 h = mesh_par from meshmode.mesh.io import generate_gmsh, FileSource print("BEGIN GEN") mesh = generate_gmsh( FileSource("blob-2d.step"), 2, order=order, force_ambient_dim=2, other_options=[ "-string", "Mesh.CharacteristicLengthMax = %s;" % h ], target_unit="MM", ) print("END GEN") elif mesh_name == "warp": mesh = mgen.generate_warped_rect_mesh(dim, order=order, nelements_side=mesh_par, group_cls=group_cls) h = 1 / mesh_par else: raise ValueError("mesh_name not recognized") # }}} vol_discr = Discretization(actx, mesh, group_factory(order)) print("h=%s -> %d elements" % (h, sum(mgrp.nelements for mgrp in mesh.groups))) bdry_connection = make_face_restriction(actx, vol_discr, group_factory(order), FACE_RESTR_INTERIOR) bdry_discr = bdry_connection.to_discr opp_face = make_opposite_face_connection(actx, bdry_connection) check_connection(actx, opp_face) bdry_x = thaw(bdry_discr.nodes()[0], actx) bdry_f = f(bdry_x) bdry_f_2 = opp_face(bdry_f) err = flat_norm(bdry_f - bdry_f_2, np.inf) eoc_rec.add_data_point(h, err) print(eoc_rec) assert (eoc_rec.order_estimate() >= order - 0.5 or eoc_rec.max_error() < 1.7e-13)
def test_all_faces_interpolation(actx_factory, group_factory, mesh_name, dim, mesh_pars, per_face_groups): if (group_factory is LegendreGaussLobattoTensorProductGroupFactory and mesh_name == "blob"): pytest.skip("tensor products not implemented on blobs") actx = actx_factory() if group_factory is LegendreGaussLobattoTensorProductGroupFactory: group_cls = TensorProductElementGroup else: group_cls = SimplexElementGroup from meshmode.discretization import Discretization from meshmode.discretization.connection import ( make_face_restriction, make_face_to_all_faces_embedding, check_connection) from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() order = 4 def f(x): return 0.1 * actx.np.sin(30 * x) for mesh_par in mesh_pars: # {{{ get mesh if mesh_name == "blob": assert dim == 2 h = mesh_par from meshmode.mesh.io import generate_gmsh, FileSource print("BEGIN GEN") mesh = generate_gmsh( FileSource("blob-2d.step"), 2, order=order, force_ambient_dim=2, other_options=[ "-string", "Mesh.CharacteristicLengthMax = %s;" % h ], target_unit="MM", ) print("END GEN") elif mesh_name == "warp": mesh = mgen.generate_warped_rect_mesh(dim, order=4, nelements_side=mesh_par, group_cls=group_cls) h = 1 / mesh_par else: raise ValueError("mesh_name not recognized") # }}} vol_discr = Discretization(actx, mesh, group_factory(order)) print("h=%s -> %d elements" % (h, sum(mgrp.nelements for mgrp in mesh.groups))) all_face_bdry_connection = make_face_restriction( actx, vol_discr, group_factory(order), FACE_RESTR_ALL, per_face_groups=per_face_groups) all_face_bdry_discr = all_face_bdry_connection.to_discr for ito_grp, ceg in enumerate(all_face_bdry_connection.groups): for ibatch, batch in enumerate(ceg.batches): assert np.array_equal( actx.to_numpy(actx.thaw(batch.from_element_indices)), np.arange(vol_discr.mesh.nelements)) if per_face_groups: assert ito_grp == batch.to_element_face else: assert ibatch == batch.to_element_face all_face_x = thaw(all_face_bdry_discr.nodes()[0], actx) all_face_f = f(all_face_x) all_face_f_2 = all_face_bdry_discr.zeros(actx) for boundary_tag in [ BTAG_ALL, FACE_RESTR_INTERIOR, ]: bdry_connection = make_face_restriction( actx, vol_discr, group_factory(order), boundary_tag, per_face_groups=per_face_groups) bdry_discr = bdry_connection.to_discr bdry_x = thaw(bdry_discr.nodes()[0], actx) bdry_f = f(bdry_x) all_face_embedding = make_face_to_all_faces_embedding( actx, bdry_connection, all_face_bdry_discr) check_connection(actx, all_face_embedding) all_face_f_2 = all_face_f_2 + all_face_embedding(bdry_f) err = flat_norm(all_face_f - all_face_f_2, np.inf) eoc_rec.add_data_point(h, err) print(eoc_rec) assert (eoc_rec.order_estimate() >= order - 0.5 or eoc_rec.max_error() < 1e-14)
def test_refinement_connection(actx_factory, refiner_cls, group_factory, mesh_name, dim, mesh_pars, mesh_order, refine_flags, visualize=False): from random import seed seed(13) # Discretization order order = 5 actx = actx_factory() from meshmode.discretization import Discretization from meshmode.discretization.connection import (make_refinement_connection, check_connection) from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() for mesh_par in mesh_pars: # {{{ get mesh if mesh_name == "circle": assert dim == 1 h = 1 / mesh_par mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, mesh_par + 1), order=mesh_order) elif mesh_name == "blob": if mesh_order == 5: pytest.xfail( "https://gitlab.tiker.net/inducer/meshmode/issues/2") assert dim == 2 mesh = get_blob_mesh(mesh_par, mesh_order) h = float(mesh_par) elif mesh_name == "warp": from meshmode.mesh.generation import generate_warped_rect_mesh mesh = generate_warped_rect_mesh(dim, order=mesh_order, n=mesh_par) h = 1 / mesh_par else: raise ValueError("mesh_name not recognized") # }}} from meshmode.mesh.processing import find_bounding_box mesh_bbox_low, mesh_bbox_high = find_bounding_box(mesh) mesh_ext = mesh_bbox_high - mesh_bbox_low def f(x): result = 1 if mesh_name == "blob": factor = 15 else: factor = 9 for iaxis in range(len(x)): result = result * actx.np.sin(factor * (x[iaxis] / mesh_ext[iaxis])) return result discr = Discretization(actx, mesh, group_factory(order)) refiner = refiner_cls(mesh) flags = refine_flags(mesh) refiner.refine(flags) connection = make_refinement_connection(actx, refiner, discr, group_factory(order)) check_connection(actx, connection) fine_discr = connection.to_discr x = thaw(actx, discr.nodes()) x_fine = thaw(actx, fine_discr.nodes()) f_coarse = f(x) f_interp = connection(f_coarse) f_true = f(x_fine) if visualize == "dots": import matplotlib.pyplot as plt x = x.get(actx.queue) err = np.array( np.log10(1e-16 + np.abs((f_interp - f_true).get(actx.queue))), dtype=float) import matplotlib.cm as cm cmap = cm.ScalarMappable(cmap=cm.jet) cmap.set_array(err) plt.scatter(x[0], x[1], c=cmap.to_rgba(err), s=20, cmap=cmap) plt.colorbar(cmap) plt.show() elif visualize == "vtk": from meshmode.discretization.visualization import make_visualizer fine_vis = make_visualizer(actx, fine_discr, mesh_order) fine_vis.write_vtk_file( "refine-fine-%s-%dd-%s.vtu" % (mesh_name, dim, mesh_par), [ ("f_interp", f_interp), ("f_true", f_true), ]) err = flat_norm(f_interp - f_true, np.inf) eoc_rec.add_data_point(h, err) order_slack = 0.5 if mesh_name == "blob" and order > 1: order_slack = 1 print(eoc_rec) assert (eoc_rec.order_estimate() >= order - order_slack or eoc_rec.max_error() < 1e-14)
def test_modal_truncation(actx_factory, nodal_group_factory, dim, mesh_pars): if nodal_group_factory is LegendreGaussLobattoTensorProductGroupFactory: group_cls = TensorProductElementGroup modal_group_factory = ModalTensorProductGroupFactory else: group_cls = SimplexElementGroup modal_group_factory = ModalSimplexGroupFactory actx = actx_factory() order = 5 truncated_order = 3 from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() def f(x): return actx.np.sin(2 * x) for mesh_par in mesh_pars: # Make the mesh mesh = mgen.generate_warped_rect_mesh(dim, order=order, nelements_side=mesh_par, group_cls=group_cls) h = 1 / mesh_par # Make discretizations nodal_disc = Discretization(actx, mesh, nodal_group_factory(order)) modal_disc = Discretization(actx, mesh, modal_group_factory(order)) # Make connections (nodal -> modal) nodal_to_modal_conn = NodalToModalDiscretizationConnection( nodal_disc, modal_disc) # And the reverse connection (modal -> nodal) modal_to_nodal_conn = ModalToNodalDiscretizationConnection( modal_disc, nodal_disc) x_nodal = thaw(nodal_disc.nodes()[0], actx) nodal_f = f(x_nodal) # Map to modal modal_f = nodal_to_modal_conn(nodal_f) # Now we compute the basis function indices corresonding # to modes > truncated_order mgrp, = modal_disc.groups mgrp_mode_ids = mgrp.basis_obj().mode_ids truncation_matrix = np.identity(len(mgrp_mode_ids)) for mode_idx, mode_id in enumerate(mgrp_mode_ids): if sum(mode_id) > truncated_order: truncation_matrix[mode_idx, mode_idx] = 0 # Zero out the modal coefficients corresponding to # the targeted modes. modal_f_data = actx.to_numpy(modal_f[0]) num_elem, _ = modal_f_data.shape for el_idx in range(num_elem): modal_f_data[el_idx] = np.dot(truncation_matrix, modal_f_data[el_idx]) modal_f_data = actx.from_numpy(modal_f_data) modal_f_truncated = DOFArray(actx, data=(modal_f_data, )) # Now map truncated modal coefficients back to nodal nodal_f_truncated = modal_to_nodal_conn(modal_f_truncated) err = flat_norm(nodal_f - nodal_f_truncated) eoc_rec.add_data_point(h, err) threshold_lower = 0.8 * truncated_order threshold_upper = 1.2 * truncated_order assert threshold_upper >= eoc_rec.order_estimate() >= threshold_lower