def get_strong_wave_op_with_discr_direct(cl_ctx, dims=2, order=4): from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dims, b=(0.5, ) * dims, n=(16, ) * dims) logger.debug("%d elements", mesh.nelements) discr = DGDiscretizationWithBoundaries(cl_ctx, mesh, order=order) source_center = np.array([0.1, 0.22, 0.33])[:dims] source_width = 0.05 source_omega = 3 sym_x = sym.nodes(mesh.dim) sym_source_center_dist = sym_x - source_center sym_t = sym.ScalarVariable("t") from meshmode.mesh import BTAG_ALL c = -0.1 sign = -1 w = sym.make_sym_array("w", dims + 1) u = w[0] v = w[1:] source_f = ( sym.sin(source_omega * sym_t) * sym.exp(-np.dot(sym_source_center_dist, sym_source_center_dist) / source_width**2)) rad_normal = sym.normal(BTAG_ALL, dims) rad_u = sym.cse(sym.interp("vol", BTAG_ALL)(u)) rad_v = sym.cse(sym.interp("vol", BTAG_ALL)(v)) rad_bc = sym.cse( sym.join_fields( 0.5 * (rad_u - sign * np.dot(rad_normal, rad_v)), 0.5 * rad_normal * (np.dot(rad_normal, rad_v) - sign * rad_u)), "rad_bc") sym_operator = ( -sym.join_fields(-c * np.dot(sym.nabla(dims), v) - source_f, -c * (sym.nabla(dims) * u)) + sym.InverseMassOperator()( sym.FaceMassOperator() (dg_flux(c, sym.int_tpair(w)) + dg_flux(c, sym.bv_tpair(BTAG_ALL, w, rad_bc))))) return (sym_operator, discr)
def test_operator_compiler_overwrite(actx_factory): """Tests that the same expression in ``eval_code`` and ``discr_code`` does not confuse the OperatorCompiler in grudge/symbolic/compiler.py. """ actx = actx_factory() ambient_dim = 2 target_order = 4 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=(8, ) * ambient_dim, order=1) discr = DiscretizationCollection(actx, mesh, order=target_order) # {{{ test sym_u = sym.nodes(ambient_dim) sym_div_u = sum(d(u) for d, u in zip(sym.nabla(ambient_dim), sym_u)) div_u = bind(discr, sym_div_u)(actx) error = bind(discr, sym.norm(2, sym.var("x")))(actx, x=div_u - discr.dim) logger.info("error: %.5e", error)
def test_incorrect_assignment_aggregation(actx_factory, ambient_dim): """Tests that the greedy assignemnt aggregation code works on a non-trivial expression (on which it didn't work at the time of writing). """ actx = actx_factory() target_order = 4 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=(8, ) * ambient_dim, order=1) discr = DiscretizationCollection(actx, mesh, order=target_order) # {{{ test with a relative norm from grudge.dof_desc import DD_VOLUME dd = DD_VOLUME sym_x = sym.make_sym_array("y", ambient_dim, dd=dd) sym_y = sym.make_sym_array("y", ambient_dim, dd=dd) sym_norm_y = sym.norm(2, sym_y, dd=dd) sym_norm_d = sym.norm(2, sym_x - sym_y, dd=dd) sym_op = sym_norm_d / sym_norm_y logger.info("%s", sym.pretty(sym_op)) # FIXME: this shouldn't raise a RuntimeError with pytest.raises(RuntimeError): bind(discr, sym_op)(actx, x=1.0, y=discr.discr_from_dd(dd).nodes()) # }}} # {{{ test with repeated mass inverses sym_minv_y = sym.cse(sym.InverseMassOperator()(sym_y), "minv_y") sym_u = make_obj_array([0.5 * sym.Ones(dd), 0.0, 0.0])[:ambient_dim] sym_div_u = sum(d(u) for d, u in zip(sym.nabla(ambient_dim), sym_u)) sym_op = sym.MassOperator(dd)(sym_u) \ + sym.MassOperator(dd)(sym_minv_y * sym_div_u) logger.info("%s", sym.pretty(sym_op)) # FIXME: this shouldn't raise a RuntimeError either bind(discr, sym_op)(actx, y=discr.discr_from_dd(dd).nodes())
def local_derivatives(self, w): """Template for the spatial derivatives of the relevant components of :math:`E` and :math:`H` """ e, h = self.split_eh(w) nabla = sym.nabla(self.dimensions) def e_curl(field): return self.space_cross_e(nabla, field) def h_curl(field): return self.space_cross_h(nabla, field) # in conservation form: u_t + A u_x = 0 return flat_obj_array((self.current - h_curl(h)), e_curl(e))
def sym_operator(self): u = sym.var("u") def flux(pair): return sym.project(pair.dd, "all_faces")(self.flux(pair)) return (-self.v.dot( sym.nabla(self.ambient_dim) * u ) + sym.InverseMassOperator()( sym.FaceMassOperator()( flux(sym.int_tpair(u)) + flux(sym.bv_tpair(sym.BTAG_ALL, u, self.inflow_u)) # FIXME: Add back support for inflow/outflow tags #+ flux(sym.bv_tpair(self.inflow_tag, u, bc_in)) #+ flux(sym.bv_tpair(self.outflow_tag, u, bc_out)) )))
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_2d_gauss_theorem(actx_factory): """Verify Gauss's theorem explicitly on a mesh""" pytest.importorskip("meshpy") from meshpy.geometry import make_circle, GeometryBuilder from meshpy.triangle import MeshInfo, build geob = GeometryBuilder() geob.add_geometry(*make_circle(1)) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info = build(mesh_info) from meshmode.mesh.io import from_meshpy mesh = from_meshpy(mesh_info, order=1) actx = actx_factory() discr = DGDiscretizationWithBoundaries(actx, mesh, order=2) def f(x): return flat_obj_array( sym.sin(3*x[0])+sym.cos(3*x[1]), sym.sin(2*x[0])+sym.cos(x[1])) gauss_err = bind(discr, sym.integral(( sym.nabla(2) * f(sym.nodes(2)) ).sum()) - # noqa: W504 sym.integral( sym.project("vol", sym.BTAG_ALL)(f(sym.nodes(2))) .dot(sym.normal(sym.BTAG_ALL, 2)), dd=sym.BTAG_ALL) )(actx) assert abs(gauss_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)] 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) discr = DiscretizationCollection(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 = actx.np.linalg.norm(df_num - df, ord=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 - 0.25
def sym_operator(self): d = self.ambient_dim w = sym.make_sym_array("w", d + 1) u = w[0] v = w[1:] # boundary conditions ------------------------------------------------- # dirichlet BCs ------------------------------------------------------- dir_u = sym.cse(sym.project("vol", self.dirichlet_tag)(u)) dir_v = sym.cse(sym.project("vol", self.dirichlet_tag)(v)) if self.dirichlet_bc_f: # FIXME from warnings import warn warn("Inhomogeneous Dirichlet conditions on the wave equation " "are still having issues.") dir_g = sym.Field("dir_bc_u") dir_bc = flat_obj_array(2 * dir_g - dir_u, dir_v) else: dir_bc = flat_obj_array(-dir_u, dir_v) dir_bc = sym.cse(dir_bc, "dir_bc") # neumann BCs --------------------------------------------------------- neu_u = sym.cse(sym.project("vol", self.neumann_tag)(u)) neu_v = sym.cse(sym.project("vol", self.neumann_tag)(v)) neu_bc = sym.cse(flat_obj_array(neu_u, -neu_v), "neu_bc") # radiation BCs ------------------------------------------------------- rad_normal = sym.normal(self.radiation_tag, d) rad_u = sym.cse(sym.project("vol", self.radiation_tag)(u)) rad_v = sym.cse(sym.project("vol", self.radiation_tag)(v)) rad_bc = sym.cse( flat_obj_array( 0.5 * (rad_u - self.sign * np.dot(rad_normal, rad_v)), 0.5 * rad_normal * (np.dot(rad_normal, rad_v) - self.sign * rad_u)), "rad_bc") # entire operator ----------------------------------------------------- nabla = sym.nabla(d) def flux(pair): return sym.project(pair.dd, "all_faces")(self.flux(pair)) result = ( -flat_obj_array(-self.c * np.dot(nabla, v), -self.c * (nabla * u)) + # noqa: W504 sym.InverseMassOperator()( sym.FaceMassOperator() (flux(sym.int_tpair(w)) + flux(sym.bv_tpair(self.dirichlet_tag, w, dir_bc)) + flux(sym.bv_tpair(self.neumann_tag, w, neu_bc)) + flux(sym.bv_tpair(self.radiation_tag, w, rad_bc))))) result[0] += self.source_f return result
def _bound_d_dx(dcoll, xyz_axis): return bind(dcoll, sym.nabla(dcoll.dim)[xyz_axis] * sym.Variable("u"), local_only=True)
def _bound_grad(dcoll): return bind(dcoll, sym.nabla(dcoll.dim) * sym.Variable("u"), local_only=True)
def _bound_grad(self): return bind(self, sym.nabla(self.dim) * sym.Variable("u"), local_only=True)
def _bound_d_dx(self, xyz_axis): return bind(self, sym.nabla(self.dim)[xyz_axis] * sym.Variable("u"), local_only=True)