예제 #1
0
    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
예제 #2
0
def get_static_trig_var_diff(dim):
    def get_mesh(n):
        return get_box_mesh(dim, -0.5*np.pi, 0.5*np.pi, n)

    sym_coords = pmbl.make_sym_vector("x", dim)
    sym_cos = pmbl.var("cos")
    sym_sin = pmbl.var("sin")

    sym_alpha = 1
    for i in range(dim):
        sym_alpha *= sym_cos(3.*sym_coords[i])
    sym_alpha = 1 + 0.2*sym_alpha

    sym_u = 1
    for i in range(dim-1):
        sym_u *= sym_sin(sym_coords[i])
    sym_u *= sym_cos(sym_coords[dim-1])

    def get_boundaries(discr, actx, t):
        boundaries = {}

        for i in range(dim-1):
            boundaries[DTAG_BOUNDARY("-"+str(i))] = NeumannDiffusionBoundary(0.)
            boundaries[DTAG_BOUNDARY("+"+str(i))] = NeumannDiffusionBoundary(0.)

        boundaries[DTAG_BOUNDARY("-"+str(dim-1))] = DirichletDiffusionBoundary(0.)
        boundaries[DTAG_BOUNDARY("+"+str(dim-1))] = DirichletDiffusionBoundary(0.)

        return boundaries

    return HeatProblem(dim, get_mesh, sym_alpha, sym_u, get_boundaries)
예제 #3
0
def get_decaying_trig(dim, alpha):
    def get_mesh(n):
        return get_box_mesh(dim, -0.5*np.pi, 0.5*np.pi, n)

    sym_coords = pmbl.make_sym_vector("x", dim)
    sym_t = pmbl.var("t")
    sym_cos = pmbl.var("cos")
    sym_sin = pmbl.var("sin")
    sym_exp = pmbl.var("exp")

    sym_u = sym_exp(-dim*alpha*sym_t)
    for i in range(dim-1):
        sym_u *= sym_sin(sym_coords[i])
    sym_u *= sym_cos(sym_coords[dim-1])

    def get_boundaries(discr, actx, t):
        boundaries = {}

        for i in range(dim-1):
            boundaries[DTAG_BOUNDARY("-"+str(i))] = NeumannDiffusionBoundary(0.)
            boundaries[DTAG_BOUNDARY("+"+str(i))] = NeumannDiffusionBoundary(0.)

        boundaries[DTAG_BOUNDARY("-"+str(dim-1))] = DirichletDiffusionBoundary(0.)
        boundaries[DTAG_BOUNDARY("+"+str(dim-1))] = DirichletDiffusionBoundary(0.)

        return boundaries

    return HeatProblem(dim, get_mesh, alpha, sym_u, get_boundaries)
예제 #4
0
def test_symbolic_evaluation(actx_factory):
    """
    Evaluate a symbolic expression by plugging in numbers and
    :class:`~meshmode.dof_array.DOFArray`s and compare the result to the equivalent
    quantity computed explicitly.
    """
    actx = actx_factory()

    mesh = generate_regular_rect_mesh(
        a=(-np.pi/2,)*2,
        b=(np.pi/2,)*2,
        nelements_per_axis=(4,)*2)

    from grudge.eager import EagerDGDiscretization
    discr = EagerDGDiscretization(actx, mesh, order=2)

    nodes = thaw(actx, discr.nodes())

    sym_coords = pmbl.make_sym_vector("x", 2)

    sym_f = (
        pmbl.var("exp")(-pmbl.var("t"))
        * pmbl.var("cos")(sym_coords[0])
        * pmbl.var("sin")(sym_coords[1]))

    t = 0.5

    f = sym.EvaluationMapper({"t": t, "x": nodes})(sym_f)

    expected_f = np.exp(-t) * actx.np.cos(nodes[0]) * actx.np.sin(nodes[1])

    assert actx.to_numpy(discr.norm(f - expected_f)/discr.norm(expected_f)) < 1e-12
예제 #5
0
    def map_vector_variable(self, expr):
        from pymbolic import make_sym_vector
        num_components = expr.num_components

        if num_components is None:
            num_components = self.ambient_dim

        return MultiVector(make_sym_vector(expr.name, num_components))
예제 #6
0
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()
예제 #7
0
def test_symbolic_div():
    """
    Compute the symbolic divergence of a vector expression and compare it to an
    expected result.
    """
    # (Equivalent to make_obj_array([pmbl.var("x")[i] for i in range(3)]))
    sym_coords = pmbl.make_sym_vector("x", 3)
    sym_x = sym_coords[0]
    sym_y = sym_coords[1]

    sym_f = make_obj_array([sym_x, sym_x * sym_y, sym_y])

    sym_div_f = sym.div(sym_f)
    expected_sym_div_f = 1 + sym_x + 0
    assert sym_div_f == expected_sym_div_f
예제 #8
0
def get_decaying_trig_truncated_domain(dim, alpha):
    def get_mesh(n):
        return get_box_mesh(dim, -0.5*np.pi, 0.25*np.pi, n)

    sym_coords = pmbl.make_sym_vector("x", dim)
    sym_t = pmbl.var("t")
    sym_cos = pmbl.var("cos")
    sym_sin = pmbl.var("sin")
    sym_exp = pmbl.var("exp")

    sym_u = sym_exp(-dim*alpha*sym_t)
    for i in range(dim-1):
        sym_u *= sym_sin(sym_coords[i])
    sym_u *= sym_cos(sym_coords[dim-1])

    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 = 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

    return HeatProblem(dim, get_mesh, alpha, sym_u, get_boundaries)
예제 #9
0
def test_diffusion_obj_array_vectorize(actx_factory):
    """
    Checks that the diffusion operator can be called with either scalars or object
    arrays for `u`.
    """
    actx = actx_factory()

    p = DecayingTrig(1, 2.)

    sym_x = pmbl.make_sym_vector("x", p.dim)
    sym_t = pmbl.var("t")

    def get_u1(x, t):
        return p.get_solution(x, t)

    def get_u2(x, t):
        return 2 * p.get_solution(x, t)

    sym_u1 = get_u1(sym_x, sym_t)
    sym_u2 = get_u2(sym_x, sym_t)

    sym_alpha1 = p.get_alpha(sym_x, sym_t, sym_u1)
    sym_alpha2 = p.get_alpha(sym_x, sym_t, sym_u2)

    assert isinstance(sym_alpha1, Number)
    assert isinstance(sym_alpha2, Number)

    alpha = sym_alpha1

    sym_diffusion_u1 = sym_diffusion(p.dim, alpha, sym_u1)
    sym_diffusion_u2 = sym_diffusion(p.dim, alpha, sym_u2)

    n = 128

    mesh = p.get_mesh(n)

    from grudge.eager import EagerDGDiscretization
    discr = EagerDGDiscretization(actx, mesh, order=4)

    nodes = thaw(actx, discr.nodes())

    t = 1.23456789

    u1 = get_u1(nodes, t)
    u2 = get_u2(nodes, t)

    alpha = p.get_alpha(nodes, t, u1)

    boundaries = p.get_boundaries(discr, actx, t)

    diffusion_u1 = diffusion_operator(discr,
                                      quad_tag=DISCR_TAG_BASE,
                                      alpha=alpha,
                                      boundaries=boundaries,
                                      u=u1)

    assert isinstance(diffusion_u1, DOFArray)

    expected_diffusion_u1 = _sym_eval(sym_diffusion_u1, x=nodes, t=t)
    rel_linf_err = actx.to_numpy(
        discr.norm(diffusion_u1 - expected_diffusion_u1, np.inf) /
        discr.norm(expected_diffusion_u1, np.inf))
    assert rel_linf_err < 1.e-5

    boundaries_vector = [boundaries, boundaries]
    u_vector = make_obj_array([u1, u2])

    diffusion_u_vector = diffusion_operator(discr,
                                            quad_tag=DISCR_TAG_BASE,
                                            alpha=alpha,
                                            boundaries=boundaries_vector,
                                            u=u_vector)

    assert isinstance(diffusion_u_vector, np.ndarray)
    assert diffusion_u_vector.shape == (2, )

    expected_diffusion_u_vector = make_obj_array([
        _sym_eval(sym_diffusion_u1, x=nodes, t=t),
        _sym_eval(sym_diffusion_u2, x=nodes, t=t)
    ])
    rel_linf_err = actx.to_numpy(
        discr.norm(diffusion_u_vector - expected_diffusion_u_vector, np.inf) /
        discr.norm(expected_diffusion_u_vector, np.inf))
    assert rel_linf_err < 1.e-5
예제 #10
0
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

    sym_x = pmbl.make_sym_vector("x", p.dim)
    sym_t = pmbl.var("t")
    sym_u = p.get_solution(sym_x, sym_t)
    sym_alpha = p.get_alpha(sym_x, sym_t, sym_u)

    assert sym_alpha == 1

    sym_diffusion_u = sym_diffusion(p.dim, sym_alpha, sym_u)

    from meshmode.interop.nodal_dg import download_nodal_dg_if_not_present
    download_nodal_dg_if_not_present()

    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())

            u_mirgecom = p.get_solution(nodes_mirgecom, t)

            diffusion_u_mirgecom = diffusion_operator(
                discr_mirgecom,
                quad_tag=DISCR_TAG_BASE,
                alpha=discr_mirgecom.zeros(actx) + 1.,
                boundaries=p.get_boundaries(discr_mirgecom, actx, t),
                u=u_mirgecom)

            discr_ndg = ndgctx.get_discr(actx)
            nodes_ndg = thaw(actx, discr_ndg.nodes())

            u_ndg = p.get_solution(nodes_ndg, t)

            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")

            def inf_norm(f):
                return actx.np.linalg.norm(f, np.inf)

            err = (inf_norm(diffusion_u_mirgecom - diffusion_u_ndg) /
                   inf_norm(diffusion_u_ndg))

            if print_err:
                diffusion_u_exact = _sym_eval(sym_diffusion_u,
                                              x=nodes_mirgecom,
                                              t=t)
                err_exact = (
                    inf_norm(diffusion_u_mirgecom - diffusion_u_exact) /
                    inf_norm(diffusion_u_exact))
                print(err, err_exact)

            assert err < 1e-9
예제 #11
0
def test_diffusion_accuracy(actx_factory,
                            problem,
                            nsteps,
                            dt,
                            scales,
                            order,
                            visualize=False):
    """
    Checks the accuracy of the diffusion operator by solving the heat equation for a
    given problem setup.
    """
    actx = actx_factory()

    p = problem

    sym_x = pmbl.make_sym_vector("x", p.dim)
    sym_t = pmbl.var("t")
    sym_u = p.get_solution(sym_x, sym_t)
    sym_alpha = p.get_alpha(sym_x, sym_t, sym_u)

    sym_diffusion_u = sym_diffusion(p.dim, sym_alpha, sym_u)

    # In order to support manufactured solutions, we modify the heat equation
    # to add a source term f. If the solution is exact, this term should be 0.
    sym_f = sym.diff(sym_t)(sym_u) - sym_diffusion_u

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for n in scales:
        mesh = p.get_mesh(n)

        from grudge.eager import EagerDGDiscretization
        from meshmode.discretization.poly_element import \
                QuadratureSimplexGroupFactory, \
                PolynomialWarpAndBlendGroupFactory
        discr = EagerDGDiscretization(
            actx,
            mesh,
            discr_tag_to_group_factory={
                DISCR_TAG_BASE: PolynomialWarpAndBlendGroupFactory(order),
                DISCR_TAG_QUAD: QuadratureSimplexGroupFactory(3 * order),
            })

        nodes = thaw(actx, discr.nodes())

        def get_rhs(t, u):
            alpha = p.get_alpha(nodes, t, u)
            if isinstance(alpha, DOFArray):
                discr_tag = DISCR_TAG_QUAD
            else:
                discr_tag = DISCR_TAG_BASE
            return (
                diffusion_operator(discr,
                                   quad_tag=discr_tag,
                                   alpha=alpha,
                                   boundaries=p.get_boundaries(discr, actx, t),
                                   u=u) + _sym_eval(sym_f, x=nodes, t=t))

        t = 0.

        u = p.get_solution(nodes, t)

        from mirgecom.integrators import rk4_step

        for _ in range(nsteps):
            u = rk4_step(u, t, dt, get_rhs)
            t += dt

        expected_u = p.get_solution(nodes, t)

        rel_linf_err = actx.to_numpy(
            discr.norm(u - expected_u, np.inf) /
            discr.norm(expected_u, np.inf))
        eoc_rec.add_data_point(1. / n, rel_linf_err)

        if visualize:
            from grudge.shortcuts import make_visualizer
            vis = make_visualizer(discr, discr.order + 3)
            vis.write_vtk_file(
                "diffusion_accuracy_{order}_{n}.vtu".format(order=order, n=n),
                [
                    ("u", u),
                    ("expected_u", expected_u),
                ])

    print("L^inf error:")
    print(eoc_rec)
    # Expected convergence rates from Hesthaven/Warburton book
    expected_order = order + 1 if order % 2 == 0 else order
    assert (eoc_rec.order_estimate() >= expected_order - 0.5
            or eoc_rec.max_error() < 1e-11)
예제 #12
0
def grad(dim, func):
    """Return the symbolic *dim*-dimensional gradient of *func*."""
    coords = pmbl.make_sym_vector("x", dim)
    return make_obj_array([diff(coords[i])(func) for i in range(dim)])
예제 #13
0
def div(vector_func):
    """Return the symbolic divergence of *vector_func*."""
    dim = len(vector_func)
    coords = pmbl.make_sym_vector("x", dim)
    return sum([diff(coords[i])(vector_func[i]) for i in range(dim)])