예제 #1
0
def wave_operator(discr, c, w):
    u = w[0]
    v = w[1:]

    dir_u = discr.project("vol", BTAG_ALL, u)
    dir_v = discr.project("vol", BTAG_ALL, v)
    dir_bval = flat_obj_array(dir_u, dir_v)
    dir_bc = flat_obj_array(-dir_u, dir_v)

    dd_quad = DOFDesc("vol", "vel_prod")
    c_quad = discr.project("vol", dd_quad, c)
    w_quad = discr.project("vol", dd_quad, w)
    u_quad = w_quad[0]
    v_quad = w_quad[1:]

    dd_allfaces_quad = DOFDesc("all_faces", "vel_prod")

    # FIXME Fix sign issue
    return (discr.inverse_mass(
        flat_obj_array(discr.weak_div(dd_quad,
                                      scalar(c_quad) * v_quad),
                       discr.weak_grad(dd_quad, c_quad *
                                       u_quad)) -  # noqa: W504
        discr.face_mass(
            dd_allfaces_quad,
            wave_flux(discr, c=c, w_tpair=interior_trace_pair(discr, w)) +
            wave_flux(
                discr, c=c, w_tpair=TracePair(BTAG_ALL, dir_bval, dir_bc)))))
예제 #2
0
def wave_flux(discr, c, w_tpair):
    dd = w_tpair.dd
    dd_quad = dd.with_qtag("vel_prod")

    u = w_tpair[0]
    v = w_tpair[1:]

    normal = thaw(u.int.array_context, discr.normal(dd))

    flux_weak = flat_obj_array(
        np.dot(v.avg, normal),
        normal * scalar(u.avg),
    )

    # upwind
    v_jump = np.dot(normal, v.int - v.ext)
    flux_weak -= flat_obj_array(
        0.5 * (u.int - u.ext),
        0.5 * normal * scalar(v_jump),
    )

    # FIMXE this flux is only correct for continuous c
    dd_allfaces_quad = dd_quad.with_dtag("all_faces")
    c_quad = discr.project("vol", dd_quad, c)
    flux_quad = discr.project(dd, dd_quad, flux_weak)

    return discr.project(dd_quad, dd_allfaces_quad, scalar(c_quad) * flux_quad)
예제 #3
0
def test_wave_stability(actx_factory,
                        problem,
                        timestep_scale,
                        order,
                        visualize=False):
    """Checks stability of the wave operator for a given problem setup.
    Adjust *timestep_scale* to get timestep close to stability limit.
    """
    actx = actx_factory()

    p = problem

    sym_u, sym_v, sym_f, sym_rhs = sym_wave(p.dim, p.sym_phi)

    mesh = p.mesh_factory(8)

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

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

    def sym_eval(expr, t):
        return sym.EvaluationMapper({"c": p.c, "x": nodes, "t": t})(expr)

    def get_rhs(t, w):
        result = wave_operator(discr, c=p.c, w=w)
        result[0] += sym_eval(sym_f, t)
        return result

    t = 0.

    u = sym_eval(sym_u, t)
    v = sym_eval(sym_v, t)

    fields = flat_obj_array(u, v)

    from mirgecom.integrators import rk4_step
    dt = timestep_scale / order**2
    for istep in range(10):
        fields = rk4_step(fields, t, dt, get_rhs)
        t += dt

    expected_u = sym_eval(sym_u, 10 * dt)
    expected_v = sym_eval(sym_v, 10 * dt)
    expected_fields = flat_obj_array(expected_u, expected_v)

    if visualize:
        from grudge.shortcuts import make_visualizer
        vis = make_visualizer(discr, discr.order)
        vis.write_vtk_file("wave_stability.vtu", [
            ("u", fields[0]),
            ("v", fields[1:]),
            ("u_expected", expected_fields[0]),
            ("v_expected", expected_fields[1:]),
        ])

    err = discr.norm(fields - expected_fields, np.inf)
    max_err = discr.norm(expected_fields, np.inf)

    assert err < max_err
예제 #4
0
def wave_flux(dcoll, c, w_tpair):
    dd = w_tpair.dd
    dd_quad = dd.with_discr_tag(DISCR_TAG_QUAD)

    u = w_tpair[0]
    v = w_tpair[1:]

    normal = thaw(u.int.array_context, op.normal(dcoll, dd))

    flux_weak = flat_obj_array(
        np.dot(v.avg, normal),
        normal * u.avg,
    )

    # upwind
    flux_weak += flat_obj_array(
        0.5 * (u.ext - u.int),
        0.5 * normal * np.dot(normal, v.ext - v.int),
    )

    # FIXME this flux is only correct for continuous c
    dd_allfaces_quad = dd_quad.with_dtag("all_faces")
    c_quad = op.project(dcoll, "vol", dd_quad, c)
    flux_quad = op.project(dcoll, dd, dd_quad, flux_weak)

    return op.project(dcoll, dd_quad, dd_allfaces_quad, c_quad * flux_quad)
예제 #5
0
def wave_operator(discr, c, w):
    u = w[0]
    v = w[1:]

    dir_u = discr.project("vol", BTAG_ALL, u)
    dir_v = discr.project("vol", BTAG_ALL, v)
    dir_bval = flat_obj_array(dir_u, dir_v)
    dir_bc = flat_obj_array(-dir_u, dir_v)

    return (
            discr.inverse_mass(
                flat_obj_array(
                    -c*discr.weak_div(v),
                    -c*discr.weak_grad(u)
                    )
                +  # noqa: W504
                discr.face_mass(
                    wave_flux(discr, c=c, w_tpair=interior_trace_pair(discr, w))
                    + wave_flux(discr, c=c, w_tpair=TracePair(
                        BTAG_ALL, interior=dir_bval, exterior=dir_bc))
                    + sum(
                        wave_flux(discr, c=c, w_tpair=tpair)
                        for tpair in cross_rank_trace_pairs(discr, w))
                    )
                )
                )
예제 #6
0
def wave_operator(dcoll, c, w):
    u = w[0]
    v = w[1:]

    dir_u = op.project(dcoll, "vol", BTAG_ALL, u)
    dir_v = op.project(dcoll, "vol", BTAG_ALL, v)
    dir_bval = flat_obj_array(dir_u, dir_v)
    dir_bc = flat_obj_array(-dir_u, dir_v)

    dd_quad = DOFDesc("vol", DISCR_TAG_QUAD)
    c_quad = op.project(dcoll, "vol", dd_quad, c)
    w_quad = op.project(dcoll, "vol", dd_quad, w)
    u_quad = w_quad[0]
    v_quad = w_quad[1:]

    dd_allfaces_quad = DOFDesc("all_faces", DISCR_TAG_QUAD)

    return (op.inverse_mass(
        dcoll,
        flat_obj_array(-op.weak_local_div(dcoll, dd_quad, c_quad * v_quad),
                       -op.weak_local_grad(dcoll, dd_quad, c_quad * u_quad))
        +  # noqa: W504
        op.face_mass(
            dcoll, dd_allfaces_quad,
            wave_flux(dcoll, c=c, w_tpair=op.interior_trace_pair(dcoll, w)) +
            wave_flux(dcoll,
                      c=c,
                      w_tpair=TracePair(
                          BTAG_ALL, interior=dir_bval, exterior=dir_bc)))))
예제 #7
0
파일: em.py 프로젝트: sll2/grudge
    def flux(self, wtpair):
        """The numerical flux for variable coefficients.

        :param flux_type: can be in [0,1] for anything between central and upwind,
          or "lf" for Lax-Friedrichs.

        As per Hesthaven and Warburton page 433.
        """

        actx = get_container_context_recursively(wtpair)
        normal = thaw(self.dcoll.normal(wtpair.dd), actx)

        if self.fixed_material:
            e, h = self.split_eh(wtpair)
            epsilon = self.epsilon
            mu = self.mu

        Z_int = (mu / epsilon)**0.5  # noqa: N806
        Y_int = 1 / Z_int  # noqa: N806
        Z_ext = (mu / epsilon)**0.5  # noqa: N806
        Y_ext = 1 / Z_ext  # noqa: N806

        if self.flux_type == "lf":
            # if self.fixed_material:
            #     max_c = (self.epsilon*self.mu)**(-0.5)

            return flat_obj_array(
                # flux e,
                1 / 2 * (
                    -self.space_cross_h(normal, h.ext - h.int)
                    # multiplication by epsilon undoes material divisor below
                    #-max_c*(epsilon*e.int - epsilon*e.ext)
                ),
                # flux h
                1 / 2 * (
                    self.space_cross_e(normal, e.ext - e.int)
                    # multiplication by mu undoes material divisor below
                    #-max_c*(mu*h.int - mu*h.ext)
                ))
        elif isinstance(self.flux_type, (int, float)):
            # see doc/maxima/maxwell.mac
            return flat_obj_array(
                # flux e,
                (-1 / (Z_int + Z_ext) * self.space_cross_h(
                    normal,
                    Z_ext * (h.ext - h.int) -
                    self.flux_type * self.space_cross_e(normal, e.ext - e.int))
                 ),
                # flux h
                (1 / (Y_int + Y_ext) * self.space_cross_e(
                    normal,
                    Y_ext * (e.ext - e.int) +
                    self.flux_type * self.space_cross_h(normal, h.ext - h.int))
                 ),
            )
        else:
            raise ValueError("maxwell: invalid flux_type (%s)" %
                             self.flux_type)
예제 #8
0
파일: em.py 프로젝트: majosm/grudge
def get_rectangular_cavity_mode(E_0, mode_indices):  # noqa: N803
    """A rectangular TM cavity mode for a rectangle / cube
    with one corner at the origin and the other at (1,1[,1])."""
    dims = len(mode_indices)
    if dims != 2 and dims != 3:
        raise ValueError("Improper mode_indices dimensions")
    import numpy

    factors = [n * numpy.pi for n in mode_indices]

    kx, ky = factors[0:2]
    if dims == 3:
        kz = factors[2]

    omega = numpy.sqrt(sum(f**2 for f in factors))

    nodes = sym.nodes(dims)
    x = nodes[0]
    y = nodes[1]
    if dims == 3:
        z = nodes[2]

    sx = sym.sin(kx * x)
    cx = sym.cos(kx * x)
    sy = sym.sin(ky * y)
    cy = sym.cos(ky * y)
    if dims == 3:
        sz = sym.sin(kz * z)
        cz = sym.cos(kz * z)

    if dims == 2:
        tfac = sym.ScalarVariable("t") * omega

        result = flat_obj_array(
            0,
            0,
            sym.sin(kx * x) * sym.sin(ky * y) * sym.cos(tfac),  # ez
            -ky * sym.sin(kx * x) * sym.cos(ky * y) * sym.sin(tfac) /
            omega,  # hx
            kx * sym.cos(kx * x) * sym.sin(ky * y) * sym.sin(tfac) /
            omega,  # hy
            0,
        )
    else:
        tdep = sym.exp(-1j * omega * sym.ScalarVariable("t"))

        gamma_squared = ky**2 + kx**2
        result = flat_obj_array(
            -kx * kz * E_0 * cx * sy * sz * tdep / gamma_squared,  # ex
            -ky * kz * E_0 * sx * cy * sz * tdep / gamma_squared,  # ey
            E_0 * sx * sy * cz * tdep,  # ez
            -1j * omega * ky * E_0 * sx * cy * cz * tdep / gamma_squared,  # hx
            1j * omega * kx * E_0 * cx * sy * cz * tdep / gamma_squared,
            0,
        )

    return result
예제 #9
0
파일: em.py 프로젝트: sll2/grudge
def get_rectangular_cavity_mode(actx, nodes, t, E_0,
                                mode_indices):  # noqa: N803
    """A rectangular TM cavity mode for a rectangle / cube
    with one corner at the origin and the other at (1,1[,1])."""
    dims = len(mode_indices)
    if dims != 2 and dims != 3:
        raise ValueError("Improper mode_indices dimensions")

    factors = [n * np.pi for n in mode_indices]

    kx, ky = factors[0:2]
    if dims == 3:
        kz = factors[2]

    omega = np.sqrt(sum(f**2 for f in factors))

    x = nodes[0]
    y = nodes[1]
    if dims == 3:
        z = nodes[2]

    zeros = 0 * x
    sx = actx.np.sin(kx * x)
    cx = actx.np.cos(kx * x)
    sy = actx.np.sin(ky * y)
    cy = actx.np.cos(ky * y)
    if dims == 3:
        sz = actx.np.sin(kz * z)
        cz = actx.np.cos(kz * z)

    if dims == 2:
        tfac = t * omega

        result = flat_obj_array(
            zeros,
            zeros,
            actx.np.sin(kx * x) * actx.np.sin(ky * y) * np.cos(tfac),  # ez
            (-ky * actx.np.sin(kx * x) * actx.np.cos(ky * y) * np.sin(tfac) /
             omega),  # hx
            (kx * actx.np.cos(kx * x) * actx.np.sin(ky * y) * np.sin(tfac) /
             omega),  # hy
            zeros,
        )
    else:
        tdep = np.exp(-1j * omega * t)

        gamma_squared = ky**2 + kx**2
        result = flat_obj_array(
            -kx * kz * E_0 * cx * sy * sz * tdep / gamma_squared,  # ex
            -ky * kz * E_0 * sx * cy * sz * tdep / gamma_squared,  # ey
            E_0 * sx * sy * cz * tdep,  # ez
            -1j * omega * ky * E_0 * sx * cy * cz * tdep / gamma_squared,  # hx
            1j * omega * kx * E_0 * cx * sy * cz * tdep / gamma_squared,
            zeros,
        )

    return result
예제 #10
0
    def operator(self, t, w):
        dcoll = self.dcoll
        u = w[0]
        v = w[1:]
        actx = u.array_context

        # boundary conditions -------------------------------------------------

        # dirichlet BCs -------------------------------------------------------
        dir_u = op.project(dcoll, "vol", self.dirichlet_tag, u)
        dir_v = op.project(dcoll, "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 = self.dirichlet_bc_f
            dir_bc = flat_obj_array(2 * dir_g - dir_u, dir_v)
        else:
            dir_bc = flat_obj_array(-dir_u, dir_v)

        # neumann BCs ---------------------------------------------------------
        neu_u = op.project(dcoll, "vol", self.neumann_tag, u)
        neu_v = op.project(dcoll, "vol", self.neumann_tag, v)
        neu_bc = flat_obj_array(neu_u, -neu_v)

        # radiation BCs -------------------------------------------------------
        rad_normal = thaw(dcoll.normal(dd=self.radiation_tag), actx)

        rad_u = op.project(dcoll, "vol", self.radiation_tag, u)
        rad_v = op.project(dcoll, "vol", self.radiation_tag, v)

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

        # entire operator -----------------------------------------------------
        def flux(tpair):
            return op.project(dcoll, tpair.dd, "all_faces", self.flux(tpair))

        result = (op.inverse_mass(
            dcoll,
            flat_obj_array(-self.c * op.weak_local_div(dcoll, v),
                           -self.c * op.weak_local_grad(dcoll, u)) -
            op.face_mass(
                dcoll,
                sum(
                    flux(tpair)
                    for tpair in op.interior_trace_pairs(dcoll, w)) +
                flux(op.bv_trace_pair(dcoll, self.dirichlet_tag, w, dir_bc)) +
                flux(op.bv_trace_pair(dcoll, self.neumann_tag, w, neu_bc)) +
                flux(op.bv_trace_pair(dcoll, self.radiation_tag, w, rad_bc)))))

        result[0] = result[0] + self.source_f(actx, dcoll, t)

        return result
예제 #11
0
    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.var("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 -----------------------------------------------------
        def flux(pair):
            return sym.project(pair.dd, "all_faces")(self.flux(pair))

        result = sym.InverseMassOperator()(flat_obj_array(
            -self.c * np.dot(sym.stiffness_t(self.ambient_dim), v), -self.c *
            (sym.stiffness_t(self.ambient_dim) * u)) - 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
예제 #12
0
 def __call__(self, x, y, three_mult=None):
     """Compute the subsetted cross product on the indexables *x* and *y*.
     :param three_mult: a function of three arguments *sign, xj, yk*
       used in place of the product *sign*xj*yk*. Defaults to just this
       product if not given.
     """
     from pytools.obj_array import flat_obj_array
     if three_mult is None:
         return flat_obj_array(*[f(x, y) for f in self.functions])
     else:
         return flat_obj_array(
                 *[sum(three_mult(lc, x[j], y[k]) for lc, j, k in lcjk)
                 for lcjk in self.component_lcjk])
예제 #13
0
def get_strong_wave_op_with_discr_direct(actx, 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(actx, 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.project("vol", BTAG_ALL)(u))
    rad_v = sym.cse(sym.project("vol", BTAG_ALL)(v))

    rad_bc = sym.cse(
        flat_obj_array(
            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 = (
        -flat_obj_array(-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)
예제 #14
0
    def flux(self, w):
        u = w[0]
        v = w[1:]
        normal = sym.normal(w.dd, self.ambient_dim)

        flux_weak = flat_obj_array(np.dot(v.avg, normal), u.avg * normal)

        if self.flux_type == "central":
            return -self.c * flux_weak
        elif self.flux_type == "upwind":
            return -self.c * (flux_weak + self.sign * flat_obj_array(
                0.5 * (u.int - u.ext), 0.5 *
                (normal * np.dot(normal, v.int - v.ext))))
        else:
            raise ValueError("invalid flux type '%s'" % self.flux_type)
예제 #15
0
def dg_flux(c, tpair):
    u = tpair[0]
    v = tpair[1:]

    dims = len(v)

    normal = sym.normal(tpair.dd, dims)
    flux_weak = flat_obj_array(np.dot(v.avg, normal), u.avg * normal)

    flux_weak -= (1 if c > 0 else -1) * flat_obj_array(
        0.5 * (u.int - u.ext), 0.5 * (normal * np.dot(normal, v.int - v.ext)))

    flux_strong = flat_obj_array(np.dot(v.int, normal),
                                 u.int * normal) - flux_weak

    return sym.project(tpair.dd, "all_faces")(c * flux_strong)
예제 #16
0
파일: em.py 프로젝트: kaushikcfd/grudge
    def absorbing_bc(self, w):
        """Construct part of the flux operator template for 1st order
        absorbing boundary conditions.
        """

        absorb_normal = sym.normal(self.absorb_tag, self.dimensions)

        e, h = self.split_eh(w)

        if self.fixed_material:
            epsilon = self.epsilon
            mu = self.mu

        absorb_Z = (mu/epsilon)**0.5  # noqa: N806
        absorb_Y = 1/absorb_Z  # noqa: N806

        absorb_e = sym.cse(sym.project("vol", self.absorb_tag)(e))
        absorb_h = sym.cse(sym.project("vol", self.absorb_tag)(h))

        bc = flat_obj_array(
                absorb_e + 1/2*(self.space_cross_h(absorb_normal, self.space_cross_e(
                    absorb_normal, absorb_e))
                    - absorb_Z*self.space_cross_h(absorb_normal, absorb_h)),
                absorb_h + 1/2*(
                    self.space_cross_e(absorb_normal, self.space_cross_h(
                        absorb_normal, absorb_h))
                    + absorb_Y*self.space_cross_e(absorb_normal, absorb_e)))

        return bc
예제 #17
0
파일: em.py 프로젝트: sll2/grudge
    def absorbing_bc(self, w):
        """Construct part of the flux operator template for 1st order
        absorbing boundary conditions.
        """

        actx = get_container_context_recursively(w)
        absorb_normal = thaw(self.dcoll.normal(dd=self.absorb_tag), actx)

        e, h = self.split_eh(w)

        if self.fixed_material:
            epsilon = self.epsilon
            mu = self.mu

        absorb_Z = (mu / epsilon)**0.5  # noqa: N806
        absorb_Y = 1 / absorb_Z  # noqa: N806

        absorb_e = op.project(self.dcoll, "vol", self.absorb_tag, e)
        absorb_h = op.project(self.dcoll, "vol", self.absorb_tag, h)

        bc = flat_obj_array(
            absorb_e + 1 / 2 *
            (self.space_cross_h(absorb_normal,
                                self.space_cross_e(absorb_normal, absorb_e)) -
             absorb_Z * self.space_cross_h(absorb_normal, absorb_h)),
            absorb_h + 1 / 2 *
            (self.space_cross_e(absorb_normal,
                                self.space_cross_h(absorb_normal, absorb_h)) +
             absorb_Y * self.space_cross_e(absorb_normal, absorb_e)))

        return bc
예제 #18
0
    def __call__(self, t, x_vec, eos=IdealSingleGas()):
        """
        Create the lump-of-mass solution at time *t* and locations *x_vec*.

        Note that *t* is used to advect the mass lump under the assumption of
        constant, and uniform velocity.

        Parameters
        ----------
        t: float
            Current time at which the solution is desired
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: :class:`mirgecom.eos.GasEOS`
            Equation of state class to be used in construction of soln (if needed)
        """
        lump_loc = self._center + t * self._velocity
        assert len(x_vec) == self._dim
        # coordinates relative to lump center
        rel_center = make_obj_array(
            [x_vec[i] - lump_loc[i] for i in range(self._dim)]
        )
        actx = x_vec[0].array_context
        r = actx.np.sqrt(np.dot(rel_center, rel_center))

        gamma = eos.gamma()
        expterm = self._rhoamp * actx.np.exp(1 - r ** 2)
        mass = expterm + self._rho0
        mom = self._velocity * mass
        energy = (self._p0 / (gamma - 1.0)) + np.dot(mom, mom) / (2.0 * mass)

        return flat_obj_array(mass, energy, mom)
예제 #19
0
    def __call__(self, t, x_vec, eos=IdealSingleGas()):
        """
        Create the isentropic vortex solution at time *t* at locations *x_vec*.

        Parameters
        ----------
        t: float
            Current time at which the solution is desired.
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: :class:`mirgecom.eos.GasEOS`
            Equation of state class to be used in construction of soln (if needed)
        """
        vortex_loc = self._center + t * self._velocity

        # coordinates relative to vortex center
        x_rel = x_vec[0] - vortex_loc[0]
        y_rel = x_vec[1] - vortex_loc[1]
        actx = x_vec[0].array_context
        gamma = eos.gamma()
        r = actx.np.sqrt(x_rel ** 2 + y_rel ** 2)
        expterm = self._beta * actx.np.exp(1 - r ** 2)
        u = self._velocity[0] - expterm * y_rel / (2 * np.pi)
        v = self._velocity[1] + expterm * x_rel / (2 * np.pi)
        mass = (1 - (gamma - 1) / (16 * gamma * np.pi ** 2)
                * expterm ** 2) ** (1 / (gamma - 1))
        p = mass ** gamma

        e = p / (gamma - 1) + mass / 2 * (u ** 2 + v ** 2)

        return flat_obj_array(mass, e, mass * u, mass * v)
예제 #20
0
def get_torus_with_ref_mean_curvature(actx, h):
    order = 4
    r_minor = 1.0
    r_major = 3.0

    from meshmode.mesh.generation import generate_torus
    mesh = generate_torus(r_major, r_minor,
            n_major=h, n_minor=h, order=order)
    discr = Discretization(actx, mesh,
        InterpolatoryQuadratureSimplexGroupFactory(order))

    from meshmode.dof_array import thaw
    nodes = thaw(actx, discr.nodes())

    # copied from meshmode.mesh.generation.generate_torus
    a = r_major
    b = r_minor

    u = actx.np.arctan2(nodes[1], nodes[0])
    from pytools.obj_array import flat_obj_array
    rvec = flat_obj_array(actx.np.cos(u), actx.np.sin(u), 0*u)
    rvec = sum(nodes * rvec) - a
    cosv = actx.np.cos(actx.np.arctan2(nodes[2], rvec))

    return discr, (a + 2.0 * b * cosv) / (2 * b * (a + b * cosv))
예제 #21
0
def get_example_stepper(actx, dims=2, order=3, use_fusion=True,
                        exec_mapper_factory=ExecutionMapper,
                        return_ic=False):
    sym_operator, discr = get_wave_op_with_discr(
            actx, dims=dims, order=3)

    if not use_fusion:
        bound_op = bind(
                discr, sym_operator,
                exec_mapper_factory=exec_mapper_factory)

        stepper = RK4TimeStepper(
                discr, "w", bound_op, 1 + discr.dim,
                get_wave_component,
                exec_mapper_factory=exec_mapper_factory)

    else:
        stepper = FusedRK4TimeStepper(
                discr, "w", sym_operator, 1 + discr.dim,
                get_wave_component,
                exec_mapper_factory=exec_mapper_factory)

    if return_ic:
        ic = flat_obj_array(discr.zeros(actx),
                [discr.zeros(actx) for i in range(discr.dim)])
        return stepper, ic

    return stepper
예제 #22
0
    def set_up_stepper(self, discr, field_var_name, sym_rhs, num_fields,
                       function_registry=base_function_registry,
                       exec_mapper_factory=ExecutionMapper):
        dt_method = LSRK4MethodBuilder(component_id=field_var_name)
        dt_code = dt_method.generate()
        self.field_var_name = field_var_name
        self.state_name = f"input_{field_var_name}"

        # Transcribe the phase.
        output_vars, results, yielded_states = transcribe_phase(
                dt_code, field_var_name, num_fields,
                "primary", sym_rhs)

        # Build the bound operator for the time integrator.
        output_t = results[0]
        output_dt = results[1]
        output_states = results[2]
        output_residuals = results[3]

        assert len(output_states) == num_fields
        assert len(output_states) == len(output_residuals)

        flattened_results = flat_obj_array(output_t, output_dt, *output_states)

        self.bound_op = bind(
                discr, flattened_results,
                function_registry=function_registry,
                exec_mapper_factory=exec_mapper_factory)
예제 #23
0
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
예제 #24
0
def test_stepper_timing(ctx_factory, use_fusion):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(
        cl_ctx, properties=cl.command_queue_properties.PROFILING_ENABLE)
    actx = PyOpenCLArrayContext(queue)

    dims = 3

    sym_operator, discr = get_strong_wave_op_with_discr_direct(actx,
                                                               dims=dims,
                                                               order=3)

    t_start = 0
    dt = 0.04
    t_end = 0.1

    ic = flat_obj_array(discr.zeros(actx),
                        [discr.zeros(actx) for i in range(discr.dim)])

    if not use_fusion:
        bound_op = bind(discr,
                        sym_operator,
                        exec_mapper_factory=ExecutionMapperWithTiming)

        stepper = RK4TimeStepper(discr,
                                 "w",
                                 bound_op,
                                 1 + discr.dim,
                                 get_strong_wave_component,
                                 exec_mapper_factory=ExecutionMapperWithTiming)

    else:
        stepper = FusedRK4TimeStepper(
            discr,
            "w",
            sym_operator,
            1 + discr.dim,
            get_strong_wave_component,
            exec_mapper_factory=ExecutionMapperWithTiming)

    step = 0

    import time
    t = time.time()
    nsteps = int(np.ceil((t_end + 1e-9) / dt))
    for (_, _, profile_data) in stepper.run(ic,
                                            t_start,
                                            dt,
                                            t_end,
                                            return_profile_data=True):
        step += 1
        tn = time.time()
        logger.info("step %d/%d: %f", step, nsteps, tn - t)
        t = tn

    logger.info("fusion? %s", use_fusion)
    for key, value in profile_data.items():
        if isinstance(value, TimingFutureList):
            print(key, value.elapsed())
예제 #25
0
파일: em.py 프로젝트: majosm/grudge
    def pmc_bc(self, w):
        "Construct part of the flux operator template for PMC boundary conditions"
        e, h = self.split_eh(w)

        pmc_e = sym.cse(sym.project("vol", self.pmc_tag)(e))
        pmc_h = sym.cse(sym.project("vol", self.pmc_tag)(h))

        return flat_obj_array(pmc_e, -pmc_h)
예제 #26
0
    def flux(self, wtpair):
        u = wtpair[0]
        v = wtpair[1:]
        actx = u.int.array_context
        normal = thaw(self.dcoll.normal(wtpair.dd), actx)

        central_flux_weak = -self.c * flat_obj_array(np.dot(v.avg, normal),
                                                     u.avg * normal)

        if self.flux_type == "central":
            return central_flux_weak
        elif self.flux_type == "upwind":
            return central_flux_weak - self.c * self.sign * flat_obj_array(
                0.5 * (u.ext - u.int), 0.5 *
                (normal * np.dot(normal, v.ext - v.int)))
        else:
            raise ValueError("invalid flux type '%s'" % self.flux_type)
예제 #27
0
 def _bound_op(self, array_context, t, *args, profile_data=None):
     context = {"t": t, self.field_var_name: flat_obj_array(*args)}
     result = self.grudge_bound_op(array_context,
                                   profile_data=profile_data,
                                   **context)
     if profile_data is not None:
         result = result[0]
     return result
예제 #28
0
    def normal(self, where):
        bdry_discr = self.get_discr(where)

        ((a, ), (b, )) = parametrization_derivative(self._setup_actx,
                                                    bdry_discr)

        nrm = 1 / (a**2 + b**2)**0.5
        return freeze(flat_obj_array(b * nrm, -a * nrm))
예제 #29
0
def test_wave_accuracy(actx_factory, problem, order, visualize=False):
    """Checks accuracy of the wave operator for a given problem setup.
    """
    actx = actx_factory()

    p = problem

    sym_u, sym_v, sym_f, sym_rhs = sym_wave(p.dim, p.sym_phi)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for n in [8, 10, 12] if p.dim == 3 else [8, 12, 16]:
        mesh = p.mesh_factory(n)

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

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

        def sym_eval(expr, t):
            return sym.EvaluationMapper({"c": p.c, "x": nodes, "t": t})(expr)

        t_check = 1.23456789

        u = sym_eval(sym_u, t_check)
        v = sym_eval(sym_v, t_check)

        fields = flat_obj_array(u, v)

        rhs = wave_operator(discr, c=p.c, w=fields)
        rhs[0] = rhs[0] + sym_eval(sym_f, t_check)

        expected_rhs = sym_eval(sym_rhs, t_check)

        rel_linf_err = actx.to_numpy(
            discr.norm(rhs - expected_rhs, np.inf) /
            discr.norm(expected_rhs, 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)
            vis.write_vtk_file(
                "wave_accuracy_{order}_{n}.vtu".format(order=order, n=n), [
                    ("u", fields[0]),
                    ("v", fields[1:]),
                    ("rhs_u_actual", rhs[0]),
                    ("rhs_v_actual", rhs[1:]),
                    ("rhs_u_expected", expected_rhs[0]),
                    ("rhs_v_expected", expected_rhs[1:]),
                ])

    print("Approximation error:")
    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-11)
예제 #30
0
 def source_f(actx, dcoll, t=0):
     source_center = np.array([0.1, 0.22, 0.33])[:dcoll.dim]
     source_width = 0.05
     source_omega = 3
     nodes = thaw(dcoll.nodes(), actx)
     source_center_dist = flat_obj_array(
         [nodes[i] - source_center[i] for i in range(dcoll.dim)])
     return (np.sin(source_omega * t) * actx.np.exp(
         -np.dot(source_center_dist, source_center_dist) / source_width**2))