Beispiel #1
0
def _euler_flow_stepper(actx, parameters):
    logging.basicConfig(format="%(message)s", level=logging.INFO)

    mesh = parameters["mesh"]
    t = parameters["time"]
    order = parameters["order"]
    t_final = parameters["tfinal"]
    initializer = parameters["initializer"]
    exittol = parameters["exittol"]
    casename = parameters["casename"]
    boundaries = parameters["boundaries"]
    eos = parameters["eos"]
    cfl = parameters["cfl"]
    dt = parameters["dt"]
    constantcfl = parameters["constantcfl"]
    nstepstatus = parameters["nstatus"]

    if t_final <= t:
        return (0.0)

    rank = 0
    dim = mesh.dim
    istep = 0

    discr = EagerDGDiscretization(actx, mesh, order=order)
    nodes = thaw(actx, discr.nodes())

    cv = initializer(nodes)
    sdt = cfl * get_inviscid_timestep(discr, eos=eos, cv=cv)

    initname = initializer.__class__.__name__
    eosname = eos.__class__.__name__
    logger.info(f"Num {dim}d order-{order} elements: {mesh.nelements}\n"
                f"Timestep:        {dt}\n"
                f"Final time:      {t_final}\n"
                f"Status freq:     {nstepstatus}\n"
                f"Initialization:  {initname}\n"
                f"EOS:             {eosname}")

    vis = make_visualizer(discr, order)

    def write_soln(state, write_status=True):
        dv = eos.dependent_vars(cv=state)
        expected_result = initializer(nodes, t=t)
        result_resid = (state - expected_result).join()
        maxerr = [
            np.max(np.abs(result_resid[i].get())) for i in range(dim + 2)
        ]
        mindv = [np.min(dvfld.get()) for dvfld in dv]
        maxdv = [np.max(dvfld.get()) for dvfld in dv]

        if write_status is True:
            statusmsg = (f"Status: Step({istep}) Time({t})\n"
                         f"------   P({mindv[0]},{maxdv[0]})\n"
                         f"------   T({mindv[1]},{maxdv[1]})\n"
                         f"------   dt,cfl = ({dt},{cfl})\n"
                         f"------   Err({maxerr})")
            logger.info(statusmsg)

        io_fields = ["cv", state]
        io_fields += eos.split_fields(dim, dv)
        io_fields.append(("exact_soln", expected_result))
        io_fields.append(("residual", result_resid))
        nameform = casename + "-{iorank:04d}-{iostep:06d}.vtu"
        visfilename = nameform.format(iorank=rank, iostep=istep)
        vis.write_vtk_file(visfilename, io_fields)

        return maxerr

    def rhs(t, q):
        return euler_operator(discr,
                              eos=eos,
                              boundaries=boundaries,
                              cv=q,
                              time=t)

    filter_order = 8
    eta = .5
    alpha = -1.0 * np.log(np.finfo(float).eps)
    nummodes = int(1)
    for _ in range(dim):
        nummodes *= int(order + dim + 1)
    nummodes /= math.factorial(int(dim))
    cutoff = int(eta * order)

    from mirgecom.filter import (exponential_mode_response_function as xmrfunc,
                                 filter_modally)
    frfunc = partial(xmrfunc, alpha=alpha, filter_order=filter_order)

    while t < t_final:

        if constantcfl is True:
            dt = sdt
        else:
            cfl = dt / sdt

        if nstepstatus > 0:
            if istep % nstepstatus == 0:
                write_soln(state=cv)

        cv = rk4_step(cv, t, dt, rhs)
        cv = make_conserved(dim,
                            q=filter_modally(discr, "vol", cutoff, frfunc,
                                             cv.join()))

        t += dt
        istep += 1

        sdt = cfl * get_inviscid_timestep(discr, eos=eos, cv=cv)

    if nstepstatus > 0:
        logger.info("Writing final dump.")
        maxerr = max(write_soln(cv, False))
    else:
        expected_result = initializer(nodes, time=t)
        maxerr = discr.norm((cv - expected_result).join(), np.inf)

    logger.info(f"Max Error: {maxerr}")
    if maxerr > exittol:
        raise ValueError("Solution failed to follow expected result.")

    return (maxerr)
Beispiel #2
0
def test_filter_function(actx_factory, dim, order, do_viz=False):
    """
    Test the stand-alone procedural interface to spectral filtering.

    Tests that filtered fields have expected attenuated higher modes.
    """
    actx = actx_factory()

    logger = logging.getLogger(__name__)
    filter_order = 1
    nel_1d = 1
    eta = .5  # filter half the modes
    # Alpha value suggested by:
    # JSH/TW Nodal DG Methods, Seciton 5.3
    # DOI: 10.1007/978-0-387-72067-8
    alpha = -1.0 * np.log(np.finfo(float).eps)

    from meshmode.mesh.generation import generate_regular_rect_mesh

    mesh = generate_regular_rect_mesh(a=(0.0, ) * dim,
                                      b=(1.0, ) * dim,
                                      nelements_per_axis=(nel_1d, ) * dim)

    discr = EagerDGDiscretization(actx, mesh, order=order)
    nodes = thaw(actx, discr.nodes())

    # number of modes see e.g.:
    # JSH/TW Nodal DG Methods, Section 10.1
    # DOI: 10.1007/978-0-387-72067-8
    nummodes = int(1)
    for _ in range(dim):
        nummodes *= int(order + dim + 1)
    nummodes /= math.factorial(int(dim))
    cutoff = int(eta * order)

    from mirgecom.filter import exponential_mode_response_function as xmrfunc
    frfunc = partial(xmrfunc, alpha=alpha, filter_order=filter_order)

    # First test a uniform field, which should pass through
    # the filter unharmed.
    from mirgecom.initializers import Uniform
    initr = Uniform(dim=dim)
    uniform_soln = initr(t=0, x_vec=nodes).join()

    from mirgecom.filter import filter_modally
    filtered_soln = filter_modally(discr, "vol", cutoff, frfunc, uniform_soln)
    soln_resid = uniform_soln - filtered_soln
    max_errors = [discr.norm(v, np.inf) for v in soln_resid]

    tol = 1e-14

    logger.info(f"Max Errors (uniform field) = {max_errors}")
    assert (np.max(max_errors) < tol)

    # construct polynomial field:
    # a0 + a1*x + a2*x*x + ....
    def polyfn(coeff):  # , x_vec):
        # r = actx.np.sqrt(np.dot(nodes, nodes))
        r = nodes[0]
        result = 0
        for n, a in enumerate(coeff):
            result += a * r**n
        return make_obj_array([result])

    # Any order {cutoff} and below fields should be unharmed
    tol = 1e-14
    field_order = int(cutoff)
    coeff = [1.0 / (i + 1) for i in range(field_order + 1)]
    field = polyfn(coeff=coeff)
    filtered_field = filter_modally(discr, "vol", cutoff, frfunc, field)
    soln_resid = field - filtered_field
    max_errors = [discr.norm(v, np.inf) for v in soln_resid]
    logger.info(f"Field = {field}")
    logger.info(f"Filtered = {filtered_field}")
    logger.info(f"Max Errors (poly) = {max_errors}")
    assert (np.max(max_errors) < tol)

    # Any order > cutoff fields should have higher modes attenuated
    threshold = 1e-3
    tol = 1e-1
    if do_viz is True:
        from grudge.shortcuts import make_visualizer
        vis = make_visualizer(discr, discr.order)

    from grudge.dof_desc import DD_VOLUME_MODAL, DD_VOLUME

    modal_map = discr.connection_from_dds(DD_VOLUME, DD_VOLUME_MODAL)

    for field_order in range(cutoff + 1, cutoff + 4):
        coeff = [1.0 / (i + 1) for i in range(field_order + 1)]
        field = polyfn(coeff=coeff)
        filtered_field = filter_modally(discr, "vol", cutoff, frfunc, field)

        unfiltered_spectrum = modal_map(field)
        filtered_spectrum = modal_map(filtered_field)
        if do_viz is True:
            spectrum_resid = unfiltered_spectrum - filtered_spectrum
            io_fields = [("unfiltered", field), ("filtered", filtered_field),
                         ("unfiltered_spectrum", unfiltered_spectrum),
                         ("filtered_spectrum", filtered_spectrum),
                         ("residual", spectrum_resid)]
            vis.write_vtk_file(f"filter_test_{field_order}.vtu", io_fields)
        field_resid = unfiltered_spectrum - filtered_spectrum
        max_errors = [discr.norm(v, np.inf) for v in field_resid]
        # fields should be different, but not too different
        assert (tol > np.max(max_errors) > threshold)