def sym_wave(dim, sym_phi): """Return symbolic expressions for the wave equation system given a desired solution. (Note: In order to support manufactured solutions, we modify the wave equation to add a source term (f). If the solution is exact, this term should be 0.) """ sym_c = pmbl.var("c") sym_coords = prim.make_sym_vector("x", dim) sym_t = pmbl.var("t") # f = phi_tt - c^2 * div(grad(phi)) sym_f = sym.diff(sym_t)(sym.diff(sym_t)(sym_phi)) - sym_c**2\ * sym.div(sym.grad(dim, sym_phi)) # u = phi_t sym_u = sym.diff(sym_t)(sym_phi) # v = c*grad(phi) sym_v = [sym_c * sym.diff(sym_coords[i])(sym_phi) for i in range(dim)] # rhs(u part) = c*div(v) + f # rhs(v part) = c*grad(u) sym_rhs = flat_obj_array(sym_c * sym.div(sym_v) + sym_f, make_obj_array([sym_c]) * sym.grad(dim, sym_u)) return sym_u, sym_v, sym_f, sym_rhs
def sym_grad(dim, expr): if isinstance(expr, ConservedVars): return make_conserved(dim, q=sym_grad(dim, expr.join())) elif isinstance(expr, np.ndarray): return np.stack(obj_array_vectorize(lambda e: sym.grad(dim, e), expr)) else: return sym.grad(dim, expr)
def get_boundaries(discr, actx, t): nodes = thaw(actx, discr.nodes()) def sym_eval(expr): return sym.EvaluationMapper({"x": nodes, "t": t})(expr) exact_u = sym_eval(sym_u) exact_grad_u = make_obj_array(sym_eval(sym.grad(dim, sym_u))) boundaries = {} for i in range(dim - 1): lower_btag = DTAG_BOUNDARY("-" + str(i)) upper_btag = DTAG_BOUNDARY("+" + str(i)) upper_grad_u = discr.project("vol", upper_btag, exact_grad_u) normal = thaw(actx, discr.normal(upper_btag)) upper_grad_u_dot_n = np.dot(upper_grad_u, normal) boundaries[lower_btag] = NeumannDiffusionBoundary(0.) boundaries[upper_btag] = NeumannDiffusionBoundary( upper_grad_u_dot_n) lower_btag = DTAG_BOUNDARY("-" + str(dim - 1)) upper_btag = DTAG_BOUNDARY("+" + str(dim - 1)) upper_u = discr.project("vol", upper_btag, exact_u) boundaries[lower_btag] = DirichletDiffusionBoundary(0.) boundaries[upper_btag] = DirichletDiffusionBoundary(upper_u) return boundaries
def get_boundaries(self, discr, actx, t): nodes = thaw(actx, discr.nodes()) sym_exact_u = self.get_solution(pmbl.make_sym_vector("x", self.dim), pmbl.var("t")) exact_u = _sym_eval(sym_exact_u, x=nodes, t=t) exact_grad_u = _sym_eval(sym.grad(self.dim, sym_exact_u), x=nodes, t=t) boundaries = {} for i in range(self.dim - 1): lower_btag = DTAG_BOUNDARY("-" + str(i)) upper_btag = DTAG_BOUNDARY("+" + str(i)) upper_grad_u = discr.project("vol", upper_btag, exact_grad_u) normal = thaw(actx, discr.normal(upper_btag)) upper_grad_u_dot_n = np.dot(upper_grad_u, normal) boundaries[lower_btag] = NeumannDiffusionBoundary(0.) boundaries[upper_btag] = NeumannDiffusionBoundary( upper_grad_u_dot_n) lower_btag = DTAG_BOUNDARY("-" + str(self.dim - 1)) upper_btag = DTAG_BOUNDARY("+" + str(self.dim - 1)) upper_u = discr.project("vol", upper_btag, exact_u) boundaries[lower_btag] = DirichletDiffusionBoundary(0.) boundaries[upper_btag] = DirichletDiffusionBoundary(upper_u) return boundaries
def test_symbolic_grad(): """ Compute the symbolic gradient of an expression and compare it to an expected result. """ sym_coords = pmbl.make_sym_vector("x", 3) sym_x = sym_coords[0] sym_y = sym_coords[1] sym_f = sym_x**2 * sym_y sym_grad_f = sym.grad(3, sym_f) expected_sym_grad_f = make_obj_array([sym_y * 2 * sym_x, sym_x**2, 0]) assert (sym_grad_f == expected_sym_grad_f).all()
def get_boundaries(discr, actx, t): nodes = thaw(actx, discr.nodes()) def sym_eval(expr): return sym.EvaluationMapper({"x": nodes, "t": t})(expr) dirichlet_lower_btag = grudge_sym.DTAG_BOUNDARY("dirichlet_lower") dirichlet_upper_btag = grudge_sym.DTAG_BOUNDARY("dirichlet_upper") neumann_lower_btag = grudge_sym.DTAG_BOUNDARY("neumann_lower") neumann_upper_btag = grudge_sym.DTAG_BOUNDARY("neumann_upper") exact_u = sym_eval(sym_u) exact_grad_u = make_obj_array(sym_eval(sym.grad(dim, sym_u))) upper_u = discr.project("vol", dirichlet_upper_btag, exact_u) upper_grad_u = discr.project("vol", neumann_upper_btag, exact_grad_u) normal = thaw(actx, discr.normal(neumann_upper_btag)) upper_grad_u_dot_n = np.dot(upper_grad_u, normal) return { dirichlet_lower_btag: DirichletDiffusionBoundary(0.), dirichlet_upper_btag: DirichletDiffusionBoundary(upper_u), neumann_lower_btag: NeumannDiffusionBoundary(0.), neumann_upper_btag: NeumannDiffusionBoundary(upper_grad_u_dot_n) }
def sym_diffusion(dim, sym_alpha, sym_u): """Return a symbolic expression for the diffusion operator applied to a function. """ return sym.div([sym_alpha * grad_i for grad_i in sym.grad(dim, sym_u)])
def sym_diffusion(dim, alpha, sym_u): """Return a symbolic expression for the diffusion operator applied to a function. """ return alpha * sym.div(sym.grad(dim, sym_u))