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_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(actx, dcoll.discr_from_dd(dd_volume).nodes()[0]) 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 = actx.np.linalg.norm(nodal_f - nodal_f_2) assert err <= 1e-13
def _signed_face_ones(actx: ArrayContext, dcoll: DiscretizationCollection, dd) -> DOFArray: assert dd.is_trace() # NOTE: ignore quadrature_tags on dd, since we only care about # the face_id here all_faces_conn = dcoll.connection_from_dds(DD_VOLUME, DOFDesc(dd.domain_tag)) signed_face_ones = dcoll.discr_from_dd(dd).zeros( actx, dtype=dcoll.real_dtype) + 1 for igrp, grp in enumerate(all_faces_conn.groups): for batch in grp.batches: i = actx.thaw(batch.to_element_indices) grp_field = signed_face_ones[igrp].reshape(-1) grp_field[i] = \ (2.0 * (batch.to_element_face % 2) - 1.0) * grp_field[i] return signed_face_ones
def main(ctx_factory, dim=2, order=4, product_tag=None, visualize=False): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # {{{ parameters # sphere radius radius = 1.0 # sphere resolution resolution = 64 if dim == 2 else 1 # cfl dt_factor = 2.0 # final time final_time = np.pi # velocity field sym_x = sym.nodes(dim) c = make_obj_array([-sym_x[1], sym_x[0], 0.0])[:dim] # flux flux_type = "lf" # }}} # {{{ discretization if dim == 2: from meshmode.mesh.generation import make_curve_mesh, ellipse mesh = make_curve_mesh(lambda t: radius * ellipse(1.0, t), np.linspace(0.0, 1.0, resolution + 1), order) elif dim == 3: from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(radius, order=4 * order, uniform_refinement_rounds=resolution) else: raise ValueError("unsupported dimension") discr_tag_to_group_factory = {} if product_tag == "none": product_tag = None else: product_tag = dof_desc.DISCR_TAG_QUAD from meshmode.discretization.poly_element import \ PolynomialWarpAndBlendGroupFactory, \ QuadratureSimplexGroupFactory discr_tag_to_group_factory[dof_desc.DISCR_TAG_BASE] = \ PolynomialWarpAndBlendGroupFactory(order) if product_tag: discr_tag_to_group_factory[product_tag] = \ QuadratureSimplexGroupFactory(order=4*order) from grudge import DiscretizationCollection discr = DiscretizationCollection( actx, mesh, discr_tag_to_group_factory=discr_tag_to_group_factory) volume_discr = discr.discr_from_dd(dof_desc.DD_VOLUME) logger.info("ndofs: %d", volume_discr.ndofs) logger.info("nelements: %d", volume_discr.mesh.nelements) # }}} # {{{ symbolic operators def f_initial_condition(x): return x[0] from grudge.models.advection import SurfaceAdvectionOperator op = SurfaceAdvectionOperator(c, flux_type=flux_type, quad_tag=product_tag) bound_op = bind(discr, op.sym_operator()) u0 = bind(discr, f_initial_condition(sym_x))(actx, t=0) def rhs(t, u): return bound_op(actx, t=t, u=u) # check velocity is tangential sym_normal = sym.surface_normal(dim, dim=dim - 1, dd=dof_desc.DD_VOLUME).as_vector() error = bind(discr, sym.norm(2, c.dot(sym_normal)))(actx) logger.info("u_dot_n: %.5e", error) # }}} # {{{ time stepping # compute time step h_min = bind(discr, sym.h_max_from_volume(discr.ambient_dim, dim=discr.dim))(actx) dt = dt_factor * h_min / order**2 nsteps = int(final_time // dt) + 1 dt = final_time / nsteps + 1.0e-15 logger.info("dt: %.5e", dt) logger.info("nsteps: %d", nsteps) from grudge.shortcuts import set_up_rk4 dt_stepper = set_up_rk4("u", dt, u0, rhs) plot = Plotter(actx, discr, order, visualize=visualize) norm = bind(discr, sym.norm(2, sym.var("u"))) norm_u = norm(actx, u=u0) step = 0 event = dt_stepper.StateComputed(0.0, 0, 0, u0) plot(event, "fld-surface-%04d" % 0) if visualize and dim == 3: from grudge.shortcuts import make_visualizer vis = make_visualizer(discr) vis.write_vtk_file("fld-surface-velocity.vtu", [("u", bind(discr, c)(actx)), ("n", bind(discr, sym_normal)(actx))], overwrite=True) df = dof_desc.DOFDesc(FACE_RESTR_INTERIOR) face_discr = discr.connection_from_dds(dof_desc.DD_VOLUME, df).to_discr face_normal = bind( discr, sym.normal(df, face_discr.ambient_dim, dim=face_discr.dim))(actx) from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(actx, face_discr) vis.write_vtk_file("fld-surface-face-normals.vtu", [("n", face_normal)], overwrite=True) for event in dt_stepper.run(t_end=final_time, max_steps=nsteps + 1): if not isinstance(event, dt_stepper.StateComputed): continue step += 1 if step % 10 == 0: norm_u = norm(actx, u=event.state_component) plot(event, "fld-surface-%04d" % step) logger.info("[%04d] t = %.5f |u| = %.5e", step, event.t, norm_u) plot(event, "fld-surface-%04d" % step)
def forward_metric_nth_derivative(actx: ArrayContext, dcoll: DiscretizationCollection, xyz_axis, ref_axes, dd=None) -> DOFArray: r"""Pointwise metric derivatives representing repeated derivatives of the physical coordinate enumerated by *xyz_axis*: :math:`x_{\mathrm{xyz\_axis}}` with respect to the coordiantes on the reference element :math:`\xi_i`: .. math:: D^\alpha x_{\mathrm{xyz\_axis}} = \frac{\partial^{|\alpha|} x_{\mathrm{xyz\_axis}} }{ \partial \xi_1^{\alpha_1}\cdots \partial \xi_m^{\alpha_m}} where :math:`\alpha` is a multi-index described by *ref_axes*. :arg xyz_axis: an integer denoting which physical coordinate to differentiate. :arg ref_axes: a :class:`tuple` of tuples indicating indices of coordinate axes of the reference element to the number of derivatives which will be taken. For example, the value ``((0, 2), (1, 1))`` indicates taking the second derivative with respect to the first axis and the first derivative with respect to the second axis. Each axis must occur only once and the tuple must be sorted by the axis index. :arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value convertible to one. Defaults to the base volume discretization. :returns: a :class:`~meshmode.dof_array.DOFArray` containing the pointwise metric derivative at each nodal coordinate. """ if dd is None: dd = DD_VOLUME inner_dd = dd.with_discr_tag(DISCR_TAG_BASE) if isinstance(ref_axes, int): ref_axes = ((ref_axes, 1), ) if not isinstance(ref_axes, tuple): raise ValueError("ref_axes must be a tuple") if tuple(sorted(ref_axes)) != ref_axes: raise ValueError("ref_axes must be sorted") if len(set(ref_axes)) != len(ref_axes): raise ValueError("ref_axes must not contain an axis more than once") from pytools import flatten flat_ref_axes = flatten([rst_axis] * n for rst_axis, n in ref_axes) from meshmode.discretization import num_reference_derivative vec = num_reference_derivative( dcoll.discr_from_dd(inner_dd), flat_ref_axes, thaw(dcoll.discr_from_dd(inner_dd).nodes(), actx)[xyz_axis]) if dd.uses_quadrature(): vec = dcoll.connection_from_dds(inner_dd, dd)(vec) return vec