Skip to content
Snippets Groups Projects
hello-grudge.py 3.93 KiB
Newer Older
  • Learn to ignore specific revisions
  • Kaushik Kulkarni's avatar
    Kaushik Kulkarni committed
    # Solves the PDE:
    # \begin{cases}
    #   u_t + 2\pi u_x = 0, \\
    #   u(0, t) = -\sin(2\pi t), \\
    #   u(x, 0) = \sin(x),
    # \end{cases}
    # on the domain $x \in [0, 2\pi]$. We closely follow Chapter 3 of
    # "Nodal Discontinuous Galerkin Methods" by Hesthaven & Warburton.
    
    # BEGINEXAMPLE
    import numpy as np
    import pyopencl as cl
    from grudge.discretization import DiscretizationCollection
    import grudge.op as op
    from meshmode.mesh.generation import generate_box_mesh
    from meshmode.array_context import PyOpenCLArrayContext
    
    from grudge.dof_desc import BoundaryDomainTag, FACE_RESTR_INTERIOR
    
    Kaushik Kulkarni's avatar
    Kaushik Kulkarni committed
    
    
    ctx = cl.create_some_context()
    queue = cl.CommandQueue(ctx)
    actx = PyOpenCLArrayContext(queue)
    
    nel = 10
    coords = np.linspace(0, 2*np.pi, nel)
    mesh = generate_box_mesh((coords,),
                             boundary_tag_to_face={"left": ["-x"],
                                                   "right": ["+x"]})
    dcoll = DiscretizationCollection(actx, mesh, order=1)
    
    
    def initial_condition(x):
        # 'x' contains ndim arrays.
        # 'x[0]' gets the first coordinate value of all the nodes
        return actx.np.sin(x[0])
    
    
    def left_boundary_condition(x, t):
        return actx.np.sin(x[0] - 2 * np.pi * t)
    
    
    def flux(dcoll, u_tpair):
        dd = u_tpair.dd
        velocity = np.array([2 * np.pi])
    
        normal = actx.thaw(dcoll.normal(dd))
    
    Kaushik Kulkarni's avatar
    Kaushik Kulkarni committed
    
        v_dot_n = np.dot(velocity, normal)
        u_upwind = actx.np.where(v_dot_n > 0,
                                 u_tpair.int, u_tpair.ext)
        return u_upwind * v_dot_n
    
    
    vol_discr = dcoll.discr_from_dd("vol")
    
    left_bndry = BoundaryDomainTag("left")
    right_bndry = BoundaryDomainTag("right")
    
    x_vol = actx.thaw(dcoll.nodes())
    x_bndry = actx.thaw(dcoll.discr_from_dd(left_bndry).nodes())
    
    Kaushik Kulkarni's avatar
    Kaushik Kulkarni committed
    
    uh = initial_condition(x_vol)
    
    dt = 0.001
    t = 0
    t_final = 0.5
    
    # timestepper loop
    while t < t_final:
        # extract the left boundary trace pair
        lbnd_tpair = op.bv_trace_pair(dcoll,
                                      dd=left_bndry,
                                      interior=uh,
                                      exterior=left_boundary_condition(x_bndry, t))
        # extract the right boundary trace pair
        rbnd_tpair = op.bv_trace_pair(dcoll,
                                      dd=right_bndry,
                                      interior=uh,
                                      exterior=op.project(dcoll, "vol",
                                                          right_bndry, uh))
        # extract the trace pairs on the interior faces
        interior_tpair = op.interior_trace_pair(dcoll,
                                                uh)
        Su = op.weak_local_grad(dcoll, uh)
    
        lift = op.face_mass(dcoll,
                            # left boundary weak-flux terms
                            op.project(dcoll,
                                       left_bndry, "all_faces",
                                       flux(dcoll, lbnd_tpair))
                            # right boundary weak-flux terms
                            + op.project(dcoll,
                                         right_bndry, "all_faces",
                                         flux(dcoll, rbnd_tpair))
                            # interior weak-flux terms
                            + op.project(dcoll,
                                         FACE_RESTR_INTERIOR, "all_faces",
                                         flux(dcoll, interior_tpair)))
    
        duh_by_dt = op.inverse_mass(dcoll,
                                    np.dot([2 * np.pi], Su) - lift)
    
        # forward euler time step
        uh = uh + dt * duh_by_dt
        t += dt
    # ENDEXAMPLE
    
    
    # Plot the solution:
    def u_exact(x, t):
        return actx.np.sin(x[0] - 2 * np.pi * t)
    
    
    assert op.norm(dcoll,
                   uh - u_exact(x_vol, t_final),
                   p=2) <= 0.1
    import matplotlib.pyplot as plt
    from arraycontext import to_numpy
    plt.plot(to_numpy(actx.np.ravel(x_vol[0][0]), actx),
             to_numpy(actx.np.ravel(uh[0]), actx), label="Numerical")
    plt.plot(to_numpy(actx.np.ravel(x_vol[0][0]), actx),
             to_numpy(actx.np.ravel(u_exact(x_vol, t_final)[0]), actx), label="Exact")
    plt.xlabel("$x$")
    plt.ylabel("$u$")
    plt.legend()
    plt.show()