Ejemplo n.º 1
0
def test_lump_rhs(actx_factory, dim, order):
    """Test the inviscid rhs using the non-trivial mass lump case.

    The case is tested against the analytic expressions of the RHS.
    Checks several different orders and refinement levels to check error behavior.
    """
    actx = actx_factory()

    tolerance = 1e-10
    maxxerr = 0.0

    from pytools.convergence import EOCRecorder

    eoc_rec = EOCRecorder()

    for nel_1d in [4, 8, 12]:
        from meshmode.mesh.generation import (
            generate_regular_rect_mesh, )

        mesh = generate_regular_rect_mesh(
            a=(-5, ) * dim,
            b=(5, ) * dim,
            nelements_per_axis=(nel_1d, ) * dim,
        )

        logger.info(f"Number of elements: {mesh.nelements}")

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

        # Init soln with Lump and expected RHS = 0
        center = np.zeros(shape=(dim, ))
        velocity = np.zeros(shape=(dim, ))
        lump = Lump(dim=dim, center=center, velocity=velocity)
        lump_soln = lump(nodes)
        boundaries = {
            BTAG_ALL: PrescribedInviscidBoundary(fluid_solution_func=lump)
        }
        inviscid_rhs = euler_operator(discr,
                                      eos=IdealSingleGas(),
                                      boundaries=boundaries,
                                      cv=lump_soln,
                                      time=0.0)
        expected_rhs = lump.exact_rhs(discr, cv=lump_soln, time=0)

        err_max = discr.norm((inviscid_rhs - expected_rhs).join(), np.inf)
        if err_max > maxxerr:
            maxxerr = err_max

        eoc_rec.add_data_point(1.0 / nel_1d, err_max)
    logger.info(f"Max error: {maxxerr}")

    logger.info(f"Error for (dim,order) = ({dim},{order}):\n" f"{eoc_rec}")

    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < tolerance)
Ejemplo n.º 2
0
def test_vortex_rhs(actx_factory, order):
    """Test the inviscid rhs using the non-trivial 2D isentropic vortex.

    The case is configured to yield rhs = 0. Checks several different orders
    and refinement levels to check error behavior.
    """
    actx = actx_factory()

    dim = 2

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    from meshmode.mesh.generation import generate_regular_rect_mesh

    for nel_1d in [32, 48, 64]:

        mesh = generate_regular_rect_mesh(
            a=(-5, ) * dim,
            b=(5, ) * dim,
            nelements_per_axis=(nel_1d, ) * dim,
        )

        logger.info(f"Number of {dim}d elements:  {mesh.nelements}")

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

        # Init soln with Vortex and expected RHS = 0
        vortex = Vortex2D(center=[0, 0], velocity=[0, 0])
        vortex_soln = vortex(nodes)
        boundaries = {
            BTAG_ALL: PrescribedInviscidBoundary(fluid_solution_func=vortex)
        }

        inviscid_rhs = euler_operator(discr,
                                      eos=IdealSingleGas(),
                                      boundaries=boundaries,
                                      cv=vortex_soln,
                                      time=0.0)

        err_max = discr.norm(inviscid_rhs.join(), np.inf)
        eoc_rec.add_data_point(1.0 / nel_1d, err_max)

    logger.info(f"Error for (dim,order) = ({dim},{order}):\n" f"{eoc_rec}")

    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-11)
Ejemplo n.º 3
0
def _get_scalar_lump():
    from mirgecom.eos import IdealSingleGas
    eos = IdealSingleGas()

    from mirgecom.initializers import MulticomponentLump
    init = MulticomponentLump(dim=2,
                              nspecies=3,
                              velocity=np.ones(2),
                              spec_y0s=np.ones(3),
                              spec_amplitudes=np.ones(3))

    from meshmode.mesh import BTAG_ALL
    from mirgecom.boundary import PrescribedInviscidBoundary
    boundaries = {
        BTAG_ALL: PrescribedInviscidBoundary(fluid_solution_func=init)
    }

    return eos, init, boundaries, 1e-12
Ejemplo n.º 4
0
def main(ctx_factory=cl.create_some_context, use_logmgr=True,
         use_leap=False, use_profiling=False, casename=None,
         rst_filename=None, actx_class=PyOpenCLArrayContext):
    """Drive example."""
    cl_ctx = ctx_factory()

    if casename is None:
        casename = "mirgecom"

    from mpi4py import MPI
    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    nparts = comm.Get_size()

    logmgr = initialize_logmgr(use_logmgr,
        filename=f"{casename}.sqlite", mode="wu", mpi_comm=comm)

    if use_profiling:
        queue = cl.CommandQueue(
            cl_ctx, properties=cl.command_queue_properties.PROFILING_ENABLE)
    else:
        queue = cl.CommandQueue(cl_ctx)

    actx = actx_class(
        queue,
        allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)))

    # timestepping control
    current_step = 0
    if use_leap:
        from leap.rk import RK4MethodBuilder
        timestepper = RK4MethodBuilder("state")
    else:
        timestepper = rk4_step
    t_final = 0.005
    current_cfl = 1.0
    current_dt = .001
    current_t = 0
    constant_cfl = False

    # some i/o frequencies
    nstatus = 1
    nrestart = 5
    nviz = 1
    nhealth = 1

    dim = 2
    rst_path = "restart_data/"
    rst_pattern = (
        rst_path + "{cname}-{step:04d}-{rank:04d}.pkl"
    )
    if rst_filename:  # read the grid from restart data
        rst_filename = f"{rst_filename}-{rank:04d}.pkl"
        from mirgecom.restart import read_restart_data
        restart_data = read_restart_data(actx, rst_filename)
        local_mesh = restart_data["local_mesh"]
        local_nelements = local_mesh.nelements
        global_nelements = restart_data["global_nelements"]
        assert restart_data["nparts"] == nparts
    else:  # generate the grid from scratch
        box_ll = -5.0
        box_ur = 5.0
        nel_1d = 16
        from meshmode.mesh.generation import generate_regular_rect_mesh
        generate_mesh = partial(generate_regular_rect_mesh, a=(box_ll,)*dim,
                                b=(box_ur,) * dim, nelements_per_axis=(nel_1d,)*dim)
        local_mesh, global_nelements = generate_and_distribute_mesh(comm,
                                                                    generate_mesh)
        local_nelements = local_mesh.nelements

    order = 3
    discr = EagerDGDiscretization(
        actx, local_mesh, order=order, mpi_communicator=comm
    )
    nodes = thaw(actx, discr.nodes())

    vis_timer = None

    if logmgr:
        logmgr_add_device_name(logmgr, queue)
        logmgr_add_device_memory_usage(logmgr, queue)
        logmgr_add_many_discretization_quantities(logmgr, discr, dim,
                             extract_vars_for_logging, units_for_logging)

        vis_timer = IntervalTimer("t_vis", "Time spent visualizing")
        logmgr.add_quantity(vis_timer)

        logmgr.add_watches([
            ("step.max", "step = {value}, "),
            ("t_sim.max", "sim time: {value:1.6e} s\n"),
            ("min_pressure", "------- P (min, max) (Pa) = ({value:1.9e}, "),
            ("max_pressure",    "{value:1.9e})\n"),
            ("t_step.max", "------- step walltime: {value:6g} s, "),
            ("t_log.max", "log walltime: {value:6g} s")
        ])

    # soln setup and init
    nspecies = 4
    centers = make_obj_array([np.zeros(shape=(dim,)) for i in range(nspecies)])
    spec_y0s = np.ones(shape=(nspecies,))
    spec_amplitudes = np.ones(shape=(nspecies,))
    eos = IdealSingleGas()
    velocity = np.ones(shape=(dim,))

    initializer = MulticomponentLump(dim=dim, nspecies=nspecies,
                                     spec_centers=centers, velocity=velocity,
                                     spec_y0s=spec_y0s,
                                     spec_amplitudes=spec_amplitudes)
    boundaries = {
        BTAG_ALL: PrescribedInviscidBoundary(fluid_solution_func=initializer)
    }

    if rst_filename:
        current_t = restart_data["t"]
        current_step = restart_data["step"]
        current_state = restart_data["state"]
        if logmgr:
            from mirgecom.logging_quantities import logmgr_set_time
            logmgr_set_time(logmgr, current_step, current_t)
    else:
        # Set the current state from time 0
        current_state = initializer(nodes)

    visualizer = make_visualizer(discr)
    initname = initializer.__class__.__name__
    eosname = eos.__class__.__name__
    init_message = make_init_message(dim=dim, order=order,
                                     nelements=local_nelements,
                                     global_nelements=global_nelements,
                                     dt=current_dt, t_final=t_final, nstatus=nstatus,
                                     nviz=nviz, cfl=current_cfl,
                                     constant_cfl=constant_cfl, initname=initname,
                                     eosname=eosname, casename=casename)
    if rank == 0:
        logger.info(init_message)

    def my_write_status(component_errors):
        if rank == 0:
            logger.info(
                "------- errors="
                + ", ".join("%.3g" % en for en in component_errors))

    def my_write_viz(step, t, state, dv=None, exact=None, resid=None):
        if dv is None:
            dv = eos.dependent_vars(state)
        if exact is None:
            exact = initializer(x_vec=nodes, eos=eos, time=t)
        if resid is None:
            resid = state - exact
        viz_fields = [("cv", state),
                      ("dv", dv),
                      ("exact", exact),
                      ("resid", resid)]
        from mirgecom.simutil import write_visfile
        write_visfile(discr, viz_fields, visualizer, vizname=casename,
                      step=step, t=t, overwrite=True, vis_timer=vis_timer)

    def my_write_restart(step, t, state):
        rst_fname = rst_pattern.format(cname=casename, step=step, rank=rank)
        if rst_fname != rst_filename:
            rst_data = {
                "local_mesh": local_mesh,
                "state": state,
                "t": t,
                "step": step,
                "order": order,
                "global_nelements": global_nelements,
                "num_parts": nparts
            }
            from mirgecom.restart import write_restart_file
            write_restart_file(actx, rst_data, rst_fname, comm)

    def my_health_check(pressure, component_errors):
        health_error = False
        from mirgecom.simutil import check_naninf_local, check_range_local
        if check_naninf_local(discr, "vol", pressure) \
           or check_range_local(discr, "vol", pressure, .99999999, 1.00000001):
            health_error = True
            logger.info(f"{rank=}: Invalid pressure data found.")

        exittol = .09
        if max(component_errors) > exittol:
            health_error = True
            if rank == 0:
                logger.info("Solution diverged from exact soln.")

        return health_error

    def my_pre_step(step, t, dt, state):
        try:
            dv = None
            exact = None
            component_errors = None

            if logmgr:
                logmgr.tick_before()

            from mirgecom.simutil import check_step
            do_viz = check_step(step=step, interval=nviz)
            do_restart = check_step(step=step, interval=nrestart)
            do_health = check_step(step=step, interval=nhealth)
            do_status = check_step(step=step, interval=nstatus)

            if do_health:
                dv = eos.dependent_vars(state)
                exact = initializer(x_vec=nodes, eos=eos, time=t)
                from mirgecom.simutil import compare_fluid_solutions
                component_errors = compare_fluid_solutions(discr, state, exact)
                from mirgecom.simutil import allsync
                health_errors = allsync(
                    my_health_check(dv.pressure, component_errors),
                    comm, op=MPI.LOR
                )
                if health_errors:
                    if rank == 0:
                        logger.info("Fluid solution failed health check.")
                    raise MyRuntimeError("Failed simulation health check.")

            if do_restart:
                my_write_restart(step=step, t=t, state=state)

            if do_viz:
                if dv is None:
                    dv = eos.dependent_vars(state)
                if exact is None:
                    exact = initializer(x_vec=nodes, eos=eos, time=t)
                resid = state - exact
                my_write_viz(step=step, t=t, state=state, dv=dv, exact=exact,
                             resid=resid)

            if do_status:
                if component_errors is None:
                    if exact is None:
                        exact = initializer(x_vec=nodes, eos=eos, time=t)
                    from mirgecom.simutil import compare_fluid_solutions
                    component_errors = compare_fluid_solutions(discr, state, exact)
                my_write_status(component_errors)

        except MyRuntimeError:
            if rank == 0:
                logger.info("Errors detected; attempting graceful exit.")
            my_write_viz(step=step, t=t, state=state)
            my_write_restart(step=step, t=t, state=state)
            raise

        dt = get_sim_timestep(discr, state, t, dt, current_cfl, eos, t_final,
                              constant_cfl)
        return state, dt

    def my_post_step(step, t, dt, state):
        # Logmgr needs to know about EOS, dt, dim?
        # imo this is a design/scope flaw
        if logmgr:
            set_dt(logmgr, dt)
            set_sim_state(logmgr, dim, state, eos)
            logmgr.tick_after()
        return state, dt

    def my_rhs(t, state):
        return euler_operator(discr, cv=state, time=t,
                              boundaries=boundaries, eos=eos)

    current_dt = get_sim_timestep(discr, current_state, current_t, current_dt,
                                  current_cfl, eos, t_final, constant_cfl)

    current_step, current_t, current_state = \
        advance_state(rhs=my_rhs, timestepper=timestepper,
                      pre_step_callback=my_pre_step, dt=current_dt,
                      post_step_callback=my_post_step,
                      state=current_state, t=current_t, t_final=t_final)

    # Dump the final data
    if rank == 0:
        logger.info("Checkpointing final state ...")

    final_dv = eos.dependent_vars(current_state)
    final_exact = initializer(x_vec=nodes, eos=eos, time=current_t)
    final_resid = current_state - final_exact
    my_write_viz(step=current_step, t=current_t, state=current_state, dv=final_dv,
                 exact=final_exact, resid=final_resid)
    my_write_restart(step=current_step, t=current_t, state=current_state)

    if logmgr:
        logmgr.close()
    elif use_profiling:
        print(actx.tabulate_profiling_data())

    finish_tol = 1e-16
    time_err = current_t - t_final
    if np.abs(time_err) > finish_tol:
        raise ValueError(f"Simulation did not finish at expected time {time_err=}.")
Ejemplo n.º 5
0
def test_isentropic_vortex(actx_factory, order):
    """Advance the 2D isentropic vortex case in time with non-zero velocities.

    This test uses an RK4 timestepping scheme, and checks the advanced field values
    against the exact/analytic expressions. This tests all parts of the Euler module
    working together, with results converging at the expected rates vs. the order.
    """
    actx = actx_factory()

    dim = 2

    from pytools.convergence import EOCRecorder

    eoc_rec = EOCRecorder()

    for nel_1d in [16, 32, 64]:
        from meshmode.mesh.generation import (
            generate_regular_rect_mesh, )

        mesh = generate_regular_rect_mesh(a=(-5.0, ) * dim,
                                          b=(5.0, ) * dim,
                                          nelements_per_axis=(nel_1d, ) * dim)

        exittol = 1.0
        t_final = 0.001
        cfl = 1.0
        vel = np.zeros(shape=(dim, ))
        orig = np.zeros(shape=(dim, ))
        vel[:dim] = 1.0
        dt = .0001
        initializer = Vortex2D(center=orig, velocity=vel)
        casename = "Vortex"
        boundaries = {
            BTAG_ALL:
            PrescribedInviscidBoundary(fluid_solution_func=initializer)
        }
        eos = IdealSingleGas()
        t = 0
        flowparams = {
            "dim": dim,
            "dt": dt,
            "order": order,
            "time": t,
            "boundaries": boundaries,
            "initializer": initializer,
            "eos": eos,
            "casename": casename,
            "mesh": mesh,
            "tfinal": t_final,
            "exittol": exittol,
            "cfl": cfl,
            "constantcfl": False,
            "nstatus": 0
        }
        maxerr = _euler_flow_stepper(actx, flowparams)
        eoc_rec.add_data_point(1.0 / nel_1d, maxerr)

    logger.info(f"Error for (dim,order) = ({dim},{order}):\n" f"{eoc_rec}")

    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-11)
Ejemplo n.º 6
0
def test_multilump_rhs(actx_factory, dim, order, v0):
    """Test the Euler rhs using the non-trivial 1, 2, and 3D mass lump case.

    The case is tested against the analytic expressions of the RHS. Checks several
    different orders and refinement levels to check error behavior.
    """
    actx = actx_factory()
    nspecies = 10
    tolerance = 1e-8
    maxxerr = 0.0

    from pytools.convergence import EOCRecorder

    eoc_rec = EOCRecorder()

    for nel_1d in [4, 8, 16]:
        from meshmode.mesh.generation import (
            generate_regular_rect_mesh, )

        mesh = generate_regular_rect_mesh(
            a=(-1, ) * dim,
            b=(1, ) * dim,
            nelements_per_axis=(nel_1d, ) * dim,
        )

        logger.info(f"Number of elements: {mesh.nelements}")

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

        centers = make_obj_array(
            [np.zeros(shape=(dim, )) for i in range(nspecies)])
        spec_y0s = np.ones(shape=(nspecies, ))
        spec_amplitudes = np.ones(shape=(nspecies, ))

        velocity = np.zeros(shape=(dim, ))
        velocity[0] = v0
        rho0 = 2.0

        lump = MulticomponentLump(dim=dim,
                                  nspecies=nspecies,
                                  rho0=rho0,
                                  spec_centers=centers,
                                  velocity=velocity,
                                  spec_y0s=spec_y0s,
                                  spec_amplitudes=spec_amplitudes)

        lump_soln = lump(nodes)
        boundaries = {
            BTAG_ALL: PrescribedInviscidBoundary(fluid_solution_func=lump)
        }

        inviscid_rhs = euler_operator(discr,
                                      eos=IdealSingleGas(),
                                      boundaries=boundaries,
                                      cv=lump_soln,
                                      time=0.0)
        expected_rhs = lump.exact_rhs(discr, cv=lump_soln, time=0)

        print(f"inviscid_rhs = {inviscid_rhs}")
        print(f"expected_rhs = {expected_rhs}")
        err_max = discr.norm((inviscid_rhs - expected_rhs).join(), np.inf)
        if err_max > maxxerr:
            maxxerr = err_max

        eoc_rec.add_data_point(1.0 / nel_1d, err_max)

        logger.info(f"Max error: {maxxerr}")

    logger.info(f"Error for (dim,order) = ({dim},{order}):\n" f"{eoc_rec}")

    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < tolerance)