Esempio n. 1
0
    def __init__(self, dcoll, c, source_f=None,
            flux_type="upwind",
            dirichlet_tag=BTAG_ALL,
            dirichlet_bc_f=0,
            neumann_tag=BTAG_NONE,
            radiation_tag=BTAG_NONE):
        """
        :arg c: a thawed (with *actx*) :class:`~meshmode.dof_array.DOFArray`
            representing the propogation speed of the wave.
        """

        if source_f is None:
            source_f = lambda actx, dcoll, t: dcoll.zeros(actx)  # noqa: E731

        actx = c.array_context
        self.dcoll = dcoll
        self.c = freeze(c)
        self.source_f = source_f

        ones = dcoll.zeros(actx) + 1
        self.sign = freeze(actx.np.where(actx.np.greater(c, 0), ones, -ones))

        self.dirichlet_tag = dirichlet_tag
        self.neumann_tag = neumann_tag
        self.radiation_tag = radiation_tag

        self.dirichlet_bc_f = dirichlet_bc_f

        self.flux_type = flux_type
Esempio n. 2
0
    def face_jacobian(self, where):
        bdry_discr = self.get_discr(where)

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

        return freeze((a**2 + b**2)**0.5)
Esempio n. 3
0
    def _area_elements():
        result = actx.np.sqrt(pseudoscalar(actx, dcoll, dd=dd).norm_squared())

        if _use_geoderiv_connection:
            result = dcoll._base_to_geoderiv_connection(dd)(result)

        return freeze(result, actx)
Esempio n. 4
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))
Esempio n. 5
0
 def _compute_characteristic_lengthscales():
     return freeze(
         DOFArray(
             actx,
             data=tuple(
                 # Scale each group array of geometric factors by the
                 # corresponding group non-geometric factor
                 cng * geo_facts for cng, geo_facts in zip(
                     dt_non_geometric_factors(dcoll),
                     thaw(dt_geometric_factors(dcoll), actx)))))
Esempio n. 6
0
    def normal(self, dd):
        r"""Get the unit normal to the specified surface discretization, *dd*.

        :arg dd: a :class:`~grudge.dof_desc.DOFDesc` as the surface discretization.
        :returns: an object array of frozen :class:`~meshmode.dof_array.DOFArray`\ s.
        """
        from arraycontext import freeze
        from grudge.geometry import normal

        return freeze(normal(self._setup_actx, self, dd))
Esempio n. 7
0
    def inverse_parametrization_derivative(self):
        [a, b], [c, d] = thaw(self.parametrization_derivative(),
                              self._setup_actx)

        result = np.zeros((2, 2), dtype=object)
        det = a * d - b * c
        result[0, 0] = d / det
        result[0, 1] = -b / det
        result[1, 0] = -c / det
        result[1, 1] = a / det

        return freeze(result)
Esempio n. 8
0
 def _inv_surf_metric_deriv():
     if ambient_dim == dim:
         imd = inverse_metric_derivative(actx,
                                         dcoll,
                                         rst_axis,
                                         xyz_axis,
                                         dd=dd)
     else:
         inv_form1 = inverse_first_fundamental_form(actx, dcoll, dd=dd)
         imd = sum(
             inv_form1[rst_axis, d] *
             forward_metric_nth_derivative(actx, dcoll, xyz_axis, d, dd=dd)
             for d in range(dim))
     return freeze(imd, actx)
Esempio n. 9
0
    def flat_centers(self):
        """Return an object array of (interleaved) center coordinates.

        ``coord_t [ambient_dim][ncenters]``
        """
        from pytential import bind, sym

        actx = self._setup_actx
        centers = bind(
            self.places,
            sym.interleaved_expansion_centers(
                self.ambient_dim, dofdesc=self.source_dd.to_stage1()))(actx)

        return freeze(flatten(centers, actx, leaf_class=DOFArray), actx)
Esempio n. 10
0
    def flat_expansion_radii(self):
        """Return an array of radii associated with the (interleaved)
        expansion centers.

        ``coord_t [ncenters]``
        """
        from pytential import bind, sym

        actx = self._setup_actx
        radii = bind(
            self.places,
            sym.expansion_radii(self.ambient_dim,
                                granularity=sym.GRANULARITY_CENTER,
                                dofdesc=self.source_dd.to_stage1()))(actx)

        return freeze(flatten(radii, actx), actx)
Esempio n. 11
0
    def _normal():
        dim = dcoll.discr_from_dd(dd).dim
        ambient_dim = dcoll.ambient_dim

        if dim == ambient_dim:
            raise ValueError(
                "may only request normals on domains whose topological "
                f"dimension ({dim}) differs from "
                f"their ambient dimension ({ambient_dim})")

        if dim == ambient_dim - 1:
            result = rel_mv_normal(actx, dcoll, dd=dd)
        else:
            # NOTE: In the case of (d - 2)-dimensional curves, we don't really have
            # enough information on the face to decide what an "exterior face normal"
            # is (e.g the "normal" to a 1D curve in 3D space is actually a
            # "normal plane")
            #
            # The trick done here is that we take the surface normal, move it to the
            # face and then take a cross product with the face tangent to get the
            # correct exterior face normal vector.
            assert dim == ambient_dim - 2

            from grudge.op import project

            volm_normal = MultiVector(
                project(
                    dcoll, dof_desc.DD_VOLUME, dd,
                    rel_mv_normal(
                        actx, dcoll,
                        dd=dof_desc.DD_VOLUME).as_vector(dtype=object)))
            pder = pseudoscalar(actx, dcoll, dd=dd)

            mv = -(volm_normal ^ pder) << volm_normal.I.inv()

            result = mv / actx.np.sqrt(mv.norm_squared())

        if _use_geoderiv_connection:
            result = dcoll._base_to_geoderiv_connection(dd)(result)

        return freeze(result, actx)
Esempio n. 12
0
    def map_common_subexpression(self, expr):
        if expr.scope == sym.cse_scope.EXPRESSION:
            cache = self.bound_expr._get_cache(EvaluationMapperCSECacheKey)
        elif expr.scope == sym.cse_scope.DISCRETIZATION:
            cache = self.places._get_cache(EvaluationMapperCSECacheKey)
        else:
            return self.rec(expr.child)

        from numbers import Number
        try:
            rec = cache[expr.child]
            if (expr.scope == sym.cse_scope.DISCRETIZATION
                    and not isinstance(rec, Number)):
                rec = thaw(rec, self.array_context)
        except KeyError:
            cached_rec = rec = self.rec(expr.child)
            if (expr.scope == sym.cse_scope.DISCRETIZATION
                    and not isinstance(rec, Number)):
                cached_rec = freeze(cached_rec, self.array_context)

            cache[expr.child] = cached_rec

        return rec
Esempio n. 13
0
    def _inv_surf_metric_deriv():
        if times_area_element:
            multiplier = area_element(
                actx,
                dcoll,
                dd=dd,
                _use_geoderiv_connection=_use_geoderiv_connection)
        else:
            multiplier = 1

        mat = actx.np.stack([
            actx.np.stack([
                multiplier * inverse_surface_metric_derivative(
                    actx,
                    dcoll,
                    rst_axis,
                    xyz_axis,
                    dd=dd,
                    _use_geoderiv_connection=_use_geoderiv_connection)
                for rst_axis in range(dcoll.dim)
            ]) for xyz_axis in range(dcoll.ambient_dim)
        ])

        return freeze(mat, actx)
Esempio n. 14
0
    def __call__(self, actx: PyOpenCLArrayContext, source_dd,
                 indices: BlockIndexRanges, **kwargs) -> BlockProxyPoints:
        """Generate proxy points for each block in *indices* with nodes in
        the discretization *source_dd*.

        :arg source_dd: a :class:`~pytential.symbolic.primitives.DOFDescriptor`
            for the discretization on which the proxy points are to be
            generated.
        """
        from pytential import sym
        source_dd = sym.as_dofdesc(source_dd)
        discr = self.places.get_discretization(source_dd.geometry,
                                               source_dd.discr_stage)

        # {{{ get proxy centers and radii

        sources = flatten(discr.nodes(), actx, leaf_class=DOFArray)

        knl = self.get_centers_knl(actx)
        _, (centers_dev, ) = knl(actx.queue,
                                 sources=sources,
                                 srcindices=indices.indices,
                                 srcranges=indices.ranges)

        knl = self.get_radii_knl(actx)
        _, (radii_dev, ) = knl(actx.queue,
                               sources=sources,
                               srcindices=indices.indices,
                               srcranges=indices.ranges,
                               radius_factor=self.radius_factor,
                               proxy_centers=centers_dev,
                               **kwargs)

        # }}}

        # {{{ build proxy points for each block

        from arraycontext import to_numpy
        centers = np.vstack(to_numpy(centers_dev, actx))
        radii = to_numpy(radii_dev, actx)

        nproxy = self.nproxy * indices.nblocks
        proxies = np.empty((self.ambient_dim, nproxy), dtype=centers.dtype)
        pxy_nr_base = 0

        for i in range(indices.nblocks):
            points = radii[i] * self.ref_points + centers[:, i].reshape(-1, 1)
            proxies[:, pxy_nr_base:pxy_nr_base + self.nproxy] = points

            pxy_nr_base += self.nproxy

        # }}}

        pxyindices = np.arange(0, nproxy, dtype=indices.indices.dtype)
        pxyranges = np.arange(0, nproxy + 1, self.nproxy)

        from arraycontext import freeze, from_numpy
        from pytential.linalg import make_block_index_from_array
        return BlockProxyPoints(
            lpot_source=self.places.get_geometry(source_dd.geometry),
            srcindices=indices,
            indices=make_block_index_from_array(pxyindices, pxyranges),
            points=freeze(from_numpy(proxies, actx), actx),
            centers=freeze(centers_dev, actx),
            radii=freeze(radii_dev, actx),
        )
Esempio n. 15
0
def dt_geometric_factors(dcoll: DiscretizationCollection, dd=None) -> DOFArray:
    r"""Computes a geometric scaling factor for each cell following [Hesthaven_2008]_,
    section 6.4, defined as the inradius (radius of an inscribed circle/sphere).

    Specifically, the inradius for each element is computed using the following
    formula from [Shewchuk_2002]_, Table 1, for simplicial cells
    (triangles/tetrahedra):

    .. math::

        r_D = \frac{d V}{\sum_{i=1}^{N_{faces}} F_i},

    where :math:`d` is the topological dimension, :math:`V` is the cell volume,
    and :math:`F_i` are the areas of each face of the cell.

    :arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value convertible to one.
        Defaults to the base volume discretization if not provided.
    :returns: a frozen :class:`~meshmode.dof_array.DOFArray` containing the
        geometric factors for each cell and at each nodal location.
    """
    from meshmode.discretization.poly_element import SimplexElementGroupBase

    if dd is None:
        dd = DD_VOLUME

    actx = dcoll._setup_actx
    volm_discr = dcoll.discr_from_dd(dd)

    if any(not isinstance(grp, SimplexElementGroupBase)
           for grp in volm_discr.groups):
        raise NotImplementedError(
            "Geometric factors are only implemented for simplex element groups"
        )

    if volm_discr.dim != volm_discr.ambient_dim:
        from warnings import warn
        warn(
            "The geometric factor for the characteristic length scale in "
            "time step estimation is not necessarily valid for non-volume-"
            "filling discretizations. Continuing anyway.",
            stacklevel=3)

    cell_vols = abs(
        op.elementwise_integral(dcoll, dd,
                                volm_discr.zeros(actx) + 1.0))

    if dcoll.dim == 1:
        return freeze(cell_vols)

    dd_face = DOFDesc("all_faces", dd.discretization_tag)
    face_discr = dcoll.discr_from_dd(dd_face)

    # To get a single value for the total surface area of a cell, we
    # take the sum over the averaged face areas on each face.
    # NOTE: The face areas are the *same* at each face nodal location.
    # This assumes there are the *same* number of face nodes on each face.
    surface_areas = abs(
        op.elementwise_integral(dcoll, dd_face,
                                face_discr.zeros(actx) + 1.0))
    surface_areas = DOFArray(
        actx,
        data=tuple(
            actx.einsum("fej->e",
                        face_ae_i.reshape(vgrp.mesh_el_group.nfaces,
                                          vgrp.nelements, afgrp.nunit_dofs),
                        tagged=(FirstAxisIsElementsTag(), )) / afgrp.nunit_dofs
            for vgrp, afgrp, face_ae_i in zip(
                volm_discr.groups, face_discr.groups, surface_areas)))

    return freeze(
        DOFArray(actx,
                 data=tuple(
                     actx.einsum("e,ei->ei",
                                 1 / sae_i,
                                 cv_i,
                                 tagged=(FirstAxisIsElementsTag(), )) *
                     dcoll.dim
                     for cv_i, sae_i in zip(cell_vols, surface_areas))))
Esempio n. 16
0
def _force_evaluation(actx, state):
    if actx is None:
        return state
    return thaw(freeze(state, actx), actx)
Esempio n. 17
0
def _advance_state_stepper_func(rhs,
                                timestepper,
                                state,
                                t_final,
                                dt=0,
                                t=0.0,
                                istep=0,
                                get_timestep=None,
                                pre_step_callback=None,
                                post_step_callback=None,
                                logmgr=None,
                                eos=None,
                                dim=None,
                                actx=None):
    """Advance state from some time (t) to some time (t_final).

    Parameters
    ----------
    rhs
        Function that should return the time derivative of the state.
        This function should take time and state as arguments, with
        a call with signature ``rhs(t, state)``.
    timestepper
        Function that advances the state from t=time to t=(time+dt), and
        returns the advanced state. Has a call with signature
        ``timestepper(state, t, dt, rhs)``.
    get_timestep
        Function that should return dt for the next step. This interface allows
        user-defined adaptive timestepping. A negative return value indicated that
        the stepper should stop gracefully. Takes only state as an argument.
    state: numpy.ndarray
        Agglomerated object array containing at least the state variables that
        will be advanced by this stepper
    t_final: float
        Simulated time at which to stop
    t: float
        Time at which to start
    dt: float
        Initial timestep size to use, optional if dt is adaptive
    istep: int
        Step number from which to start
    pre_step_callback
        An optional user-defined function, with signature:
        ``state, dt = pre_step_callback(step, t, dt, state)``,
        to be called before the timestepper is called for that particular step.
    post_step_callback
        An optional user-defined function, with signature:
        ``state, dt = post_step_callback(step, t, dt, state)``,
        to be called after the timestepper is called for that particular step.

    Returns
    -------
    istep: int
        the current step number
    t: float
        the current time
    state: numpy.ndarray
    """
    t = np.float64(t)

    if t_final <= t:
        return istep, t, state

    if actx is None:
        actx = state.array_context

    compiled_rhs = compile_rhs(actx, rhs, state)

    while t < t_final:
        state = thaw(freeze(state, actx), actx)

        if logmgr:
            logmgr.tick_before()

        if pre_step_callback is not None:
            state, dt = pre_step_callback(state=state, step=istep, t=t, dt=dt)

        state = timestepper(state=state, t=t, dt=dt, rhs=compiled_rhs)

        t += dt
        istep += 1

        if post_step_callback is not None:
            state, dt = post_step_callback(state=state, step=istep, t=t, dt=dt)

        if logmgr:
            set_dt(logmgr, dt)
            set_sim_state(logmgr, dim, state, eos)
            logmgr.tick_after()

    return istep, t, state
Esempio n. 18
0
 def parametrization_derivative(self):
     return freeze(
         parametrization_derivative(self._setup_actx, self.volume_discr))
Esempio n. 19
0
 def _flat_expansion_radii(dofdesc):
     radii = bind(
             bound_expr.places,
             sym.expansion_radii(self.ambient_dim, dofdesc=dofdesc),
             )(actx)
     return freeze(flatten(radii, actx), actx)
Esempio n. 20
0
 def _area_elements():
     return freeze(
         actx.np.sqrt(pseudoscalar(actx, dcoll, dd=dd).norm_squared()),
         actx)
Esempio n. 21
0
def main(snapshot_pattern="wave-mpi-{step:04d}-{rank:04d}.pkl", restart_step=None,
         use_profiling=False, use_logmgr=False, actx_class=PyOpenCLArrayContext):
    """Drive the example."""
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)

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

    logmgr = initialize_logmgr(use_logmgr,
        filename="wave-mpi.sqlite", mode="wu", mpi_comm=comm)
    if use_profiling:
        queue = cl.CommandQueue(cl_ctx,
            properties=cl.command_queue_properties.PROFILING_ENABLE)
        actx = actx_class(queue,
            allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)),
            logmgr=logmgr)
    else:
        queue = cl.CommandQueue(cl_ctx)
        actx = actx_class(queue,
            allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)))

    if restart_step is None:

        from meshmode.distributed import MPIMeshDistributor, get_partition_by_pymetis
        mesh_dist = MPIMeshDistributor(comm)

        dim = 2
        nel_1d = 16

        if mesh_dist.is_mananger_rank():
            from meshmode.mesh.generation import generate_regular_rect_mesh
            mesh = generate_regular_rect_mesh(
                a=(-0.5,)*dim, b=(0.5,)*dim,
                nelements_per_axis=(nel_1d,)*dim)

            print("%d elements" % mesh.nelements)
            part_per_element = get_partition_by_pymetis(mesh, num_parts)
            local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element, num_parts)

            del mesh

        else:
            local_mesh = mesh_dist.receive_mesh_part()

        fields = None

    else:
        from mirgecom.restart import read_restart_data
        restart_data = read_restart_data(
            actx, snapshot_pattern.format(step=restart_step, rank=rank)
        )
        local_mesh = restart_data["local_mesh"]
        nel_1d = restart_data["nel_1d"]
        assert comm.Get_size() == restart_data["num_parts"]

    order = 3

    discr = EagerDGDiscretization(actx, local_mesh, order=order,
                                  mpi_communicator=comm)

    current_cfl = 0.485
    wave_speed = 1.0
    from grudge.dt_utils import characteristic_lengthscales
    dt = current_cfl * characteristic_lengthscales(actx, discr) / wave_speed

    from grudge.op import nodal_min
    dt = nodal_min(discr, "vol", dt)

    t_final = 1

    if restart_step is None:
        t = 0
        istep = 0

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

    else:
        t = restart_data["t"]
        istep = restart_step
        assert istep == restart_step
        restart_fields = restart_data["fields"]
        old_order = restart_data["order"]
        if old_order != order:
            old_discr = EagerDGDiscretization(actx, local_mesh, order=old_order,
                                              mpi_communicator=comm)
            from meshmode.discretization.connection import make_same_mesh_connection
            connection = make_same_mesh_connection(actx, discr.discr_from_dd("vol"),
                                                   old_discr.discr_from_dd("vol"))
            fields = connection(restart_fields)
        else:
            fields = restart_fields

    if logmgr:
        logmgr_add_cl_device_info(logmgr, queue)
        logmgr_add_device_memory_usage(logmgr, queue)

        logmgr.add_watches(["step.max", "t_step.max", "t_log.max"])

        try:
            logmgr.add_watches(["memory_usage_python.max", "memory_usage_gpu.max"])
        except KeyError:
            pass

        if use_profiling:
            logmgr.add_watches(["multiply_time.max"])

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

    vis = make_visualizer(discr)

    def rhs(t, w):
        return wave_operator(discr, c=wave_speed, w=w)

    compiled_rhs = actx.compile(rhs)

    while t < t_final:
        if logmgr:
            logmgr.tick_before()

        # restart must happen at beginning of step
        if istep % 100 == 0 and (
                # Do not overwrite the restart file that we just read.
                istep != restart_step):
            from mirgecom.restart import write_restart_file
            write_restart_file(
                actx, restart_data={
                    "local_mesh": local_mesh,
                    "order": order,
                    "fields": fields,
                    "t": t,
                    "step": istep,
                    "nel_1d": nel_1d,
                    "num_parts": num_parts},
                filename=snapshot_pattern.format(step=istep, rank=rank),
                comm=comm
            )

        if istep % 10 == 0:
            print(istep, t, discr.norm(fields[0]))
            vis.write_parallel_vtk_file(
                comm,
                "fld-wave-mpi-%03d-%04d.vtu" % (rank, istep),
                [
                    ("u", fields[0]),
                    ("v", fields[1:]),
                ], overwrite=True
            )

        fields = thaw(freeze(fields, actx), actx)
        fields = rk4_step(fields, t, dt, compiled_rhs)

        t += dt
        istep += 1

        if logmgr:
            set_dt(logmgr, dt)
            logmgr.tick_after()

    final_soln = discr.norm(fields[0])
    assert np.abs(final_soln - 0.04409852463947439) < 1e-14
Esempio n. 22
0
def main(ctx_factory, dim=2, order=3, visualize=False, lazy=False):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)

    if lazy:
        actx = PytatoPyOpenCLArrayContext(queue)
    else:
        actx = PyOpenCLArrayContext(
            queue,
            allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)),
            force_device_scalars=True,
        )

    comm = MPI.COMM_WORLD
    num_parts = comm.Get_size()

    from meshmode.distributed import MPIMeshDistributor, get_partition_by_pymetis
    mesh_dist = MPIMeshDistributor(comm)

    nel_1d = 16

    if mesh_dist.is_mananger_rank():
        from meshmode.mesh.generation import generate_regular_rect_mesh
        mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                          b=(0.5, ) * dim,
                                          nelements_per_axis=(nel_1d, ) * dim)

        logger.info("%d elements", mesh.nelements)

        part_per_element = get_partition_by_pymetis(mesh, num_parts)

        local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element,
                                               num_parts)

        del mesh

    else:
        local_mesh = mesh_dist.receive_mesh_part()

    dcoll = DiscretizationCollection(actx,
                                     local_mesh,
                                     order=order,
                                     mpi_communicator=comm)

    fields = WaveState(u=bump(actx, dcoll),
                       v=make_obj_array(
                           [dcoll.zeros(actx) for i in range(dcoll.dim)]))

    c = 1
    dt = actx.to_numpy(0.45 * estimate_rk4_timestep(actx, dcoll, c))

    vis = make_visualizer(dcoll)

    def rhs(t, w):
        return wave_operator(dcoll, c=c, w=w)

    compiled_rhs = actx.compile(rhs)

    if comm.rank == 0:
        logger.info("dt = %g", dt)

    import time
    start = time.time()

    t = 0
    t_final = 3
    istep = 0
    while t < t_final:
        if lazy:
            fields = thaw(freeze(fields, actx), actx)

        fields = rk4_step(fields, t, dt, compiled_rhs)

        l2norm = actx.to_numpy(op.norm(dcoll, fields.u, 2))

        if istep % 10 == 0:
            stop = time.time()
            linfnorm = actx.to_numpy(op.norm(dcoll, fields.u, np.inf))
            nodalmax = actx.to_numpy(op.nodal_max(dcoll, "vol", fields.u))
            nodalmin = actx.to_numpy(op.nodal_min(dcoll, "vol", fields.u))
            if comm.rank == 0:
                logger.info(f"step: {istep} t: {t} "
                            f"L2: {l2norm} "
                            f"Linf: {linfnorm} "
                            f"sol max: {nodalmax} "
                            f"sol min: {nodalmin} "
                            f"wall: {stop-start} ")
            if visualize:
                vis.write_parallel_vtk_file(
                    comm, f"fld-wave-eager-mpi-{{rank:03d}}-{istep:04d}.vtu", [
                        ("u", fields.u),
                        ("v", fields.v),
                    ])
            start = stop

        t += dt
        istep += 1

        # NOTE: These are here to ensure the solution is bounded for the
        # time interval specified
        assert l2norm < 1
Esempio n. 23
0
def main(use_profiling=False, use_logmgr=False, lazy_eval: bool = False):
    """Drive the example."""
    cl_ctx = cl.create_some_context()

    logmgr = initialize_logmgr(use_logmgr, filename="wave.sqlite", mode="wu")

    if use_profiling:
        if lazy_eval:
            raise RuntimeError("Cannot run lazy with profiling.")
        queue = cl.CommandQueue(
            cl_ctx, properties=cl.command_queue_properties.PROFILING_ENABLE)
        actx = PyOpenCLProfilingArrayContext(
            queue,
            allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)))
    else:
        queue = cl.CommandQueue(cl_ctx)
        if lazy_eval:
            actx = PytatoPyOpenCLArrayContext(queue)
        else:
            actx = PyOpenCLArrayContext(
                queue,
                allocator=cl_tools.MemoryPool(
                    cl_tools.ImmediateAllocator(queue)))

    dim = 2
    nel_1d = 16
    from meshmode.mesh.generation import generate_regular_rect_mesh

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

    order = 3

    discr = EagerDGDiscretization(actx, mesh, order=order)

    current_cfl = 0.485
    wave_speed = 1.0
    from grudge.dt_utils import characteristic_lengthscales
    nodal_dt = characteristic_lengthscales(actx, discr) / wave_speed
    from grudge.op import nodal_min
    dt = actx.to_numpy(current_cfl * nodal_min(discr, "vol", nodal_dt))[()]

    print("%d elements" % mesh.nelements)

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

    if logmgr:
        logmgr_add_cl_device_info(logmgr, queue)
        logmgr_add_device_memory_usage(logmgr, queue)

        logmgr.add_watches(["step.max", "t_step.max", "t_log.max"])

        try:
            logmgr.add_watches(
                ["memory_usage_python.max", "memory_usage_gpu.max"])
        except KeyError:
            pass

        if use_profiling:
            logmgr.add_watches(["multiply_time.max"])

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

    vis = make_visualizer(discr)

    def rhs(t, w):
        return wave_operator(discr, c=wave_speed, w=w)

    compiled_rhs = actx.compile(rhs)

    t = 0
    t_final = 1
    istep = 0
    while t < t_final:
        if logmgr:
            logmgr.tick_before()

        fields = thaw(freeze(fields, actx), actx)
        fields = rk4_step(fields, t, dt, compiled_rhs)

        if istep % 10 == 0:
            if use_profiling:
                print(actx.tabulate_profiling_data())
            print(istep, t, actx.to_numpy(discr.norm(fields[0], np.inf)))
            vis.write_vtk_file("fld-wave-%04d.vtu" % istep, [
                ("u", fields[0]),
                ("v", fields[1:]),
            ],
                               overwrite=True)

        t += dt
        istep += 1

        if logmgr:
            set_dt(logmgr, dt)
            logmgr.tick_after()
Esempio n. 24
0
 def _flat_nodes(dofdesc):
     discr = bound_expr.places.get_discretization(
             dofdesc.geometry, dofdesc.discr_stage)
     return freeze(flatten(discr.nodes(), actx, leaf_class=DOFArray), actx)
Esempio n. 25
0
def _advance_state_leap(rhs,
                        timestepper,
                        state,
                        t_final,
                        dt=0,
                        component_id="state",
                        t=0.0,
                        istep=0,
                        get_timestep=None,
                        pre_step_callback=None,
                        post_step_callback=None,
                        logmgr=None,
                        eos=None,
                        dim=None,
                        actx=None):
    """Advance state from some time *t* to some time *t_final* using :mod:`leap`.

    Parameters
    ----------
    rhs
        Function that should return the time derivative of the state.
        This function should take time and state as arguments, with
        a call with signature ``rhs(t, state)``.
    timestepper
        An instance of :class:`leap.MethodBuilder`.
    get_timestep
        Function that should return dt for the next step. This interface allows
        user-defined adaptive timestepping. A negative return value indicated that
        the stepper should stop gracefully.
    state: numpy.ndarray
        Agglomerated object array containing at least the state variables that
        will be advanced by this stepper
    t_final: float
        Simulated time at which to stop
    component_id
        State id (required input for leap method generation)
    t: float
        Time at which to start
    dt: float
        Initial timestep size to use, optional if dt is adaptive
    istep: int
        Step number from which to start
    pre_step_callback
        An optional user-defined function, with signature:
        ``state, dt = pre_step_callback(step, t, dt, state)``,
        to be called before the timestepper is called for that particular step.
    post_step_callback
        An optional user-defined function, with signature:
        ``state, dt = post_step_callback(step, t, dt, state)``,
        to be called after the timestepper is called for that particular step.

    Returns
    -------
    istep: int
        the current step number
    t: float
        the current time
    state: numpy.ndarray
    """
    if t_final <= t:
        return istep, t, state

    if actx is None:
        actx = state.array_context

    compiled_rhs = compile_rhs(actx, rhs, state)
    stepper_cls = generate_singlerate_leap_advancer(timestepper, component_id,
                                                    compiled_rhs, t, dt, state)
    while t < t_final:

        # This is only needed because Leap testing in test/test_time_integrators.py
        # tests on single scalar values rather than an array-context-ready array
        # container like a CV.
        if isinstance(state, np.ndarray):
            state = thaw(freeze(state, actx), actx)

        if pre_step_callback is not None:
            state, dt = pre_step_callback(state=state, step=istep, t=t, dt=dt)
            stepper_cls.dt = dt

        # Leap interface here is *a bit* different.
        for event in stepper_cls.run(t_end=t + dt):
            if isinstance(event, stepper_cls.StateComputed):
                state = event.state_component
                t += dt

                if post_step_callback is not None:
                    state, dt = post_step_callback(state=state,
                                                   step=istep,
                                                   t=t,
                                                   dt=dt)
                    stepper_cls.dt = dt

                istep += 1

    return istep, t, state
Esempio n. 26
0
 def _flat_centers(dofdesc, qbx_forced_limit):
     centers = bind(bound_expr.places,
             sym.expansion_centers(
                 self.ambient_dim, qbx_forced_limit, dofdesc=dofdesc),
             )(actx)
     return freeze(flatten(centers, actx, leaf_class=DOFArray), actx)
Esempio n. 27
0
 def vol_jacobian(self):
     [a, b], [c, d] = thaw(self.parametrization_derivative(),
                           self._setup_actx)
     return freeze(a * d - b * c)