Esempio n. 1
0
def main(write_output=True):
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(
        queue,
        allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)),
        force_device_scalars=True,
    )

    from meshmode.mesh import BTAG_ALL
    from meshmode.mesh.generation import generate_warped_rect_mesh
    mesh = generate_warped_rect_mesh(dim=2, order=4, nelements_side=6)

    dcoll = DiscretizationCollection(actx, mesh, order=4)

    nodes = thaw(dcoll.nodes(), actx)
    bdry_nodes = thaw(dcoll.nodes(dd=BTAG_ALL), actx)
    bdry_normals = thaw(dcoll.normal(dd=BTAG_ALL), actx)

    if write_output:
        vis = shortcuts.make_visualizer(dcoll)
        vis.write_vtk_file("geo.vtu", [("nodes", nodes)])

        bvis = shortcuts.make_boundary_visualizer(dcoll)
        bvis.write_vtk_file("bgeo.vtu", [("bdry normals", bdry_normals),
                                         ("bdry nodes", bdry_nodes)])
Esempio n. 2
0
def test_nodal_dg_interop(actx_factory, dim):
    pytest.importorskip("oct2py")
    actx = actx_factory()

    from meshmode.interop.nodal_dg import download_nodal_dg_if_not_present
    download_nodal_dg_if_not_present()
    order = 4

    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=(8, ) * dim,
                                      order=order)

    from meshmode.interop.nodal_dg import NodalDGContext
    with NodalDGContext("./nodal-dg/Codes1.1") as ndgctx:
        ndgctx.set_mesh(mesh, order=order)

        discr = ndgctx.get_discr(actx)

        for ax in range(dim):
            x_ax = ndgctx.pull_dof_array(actx, ndgctx.AXES[ax])
            err = flat_norm(x_ax - thaw(discr.nodes()[ax], actx), np.inf)
            assert err < 1e-15

        n0 = thaw(discr.nodes()[0], actx)

        ndgctx.push_dof_array("n0", n0)
        n0_2 = ndgctx.pull_dof_array(actx, "n0")

        assert flat_norm(n0 - n0_2, np.inf) < 1e-15
Esempio n. 3
0
def test_mesh_without_vertices(actx_factory):
    actx = actx_factory()

    # create a mesh
    mesh = mgen.generate_icosphere(r=1.0, order=4)

    # create one without the vertices
    grp, = mesh.groups
    groups = [
        grp.copy(nodes=grp.nodes, vertex_indices=None) for grp in mesh.groups
    ]
    mesh = Mesh(None, groups, is_conforming=False)

    # try refining it
    from meshmode.mesh.refinement import refine_uniformly
    mesh = refine_uniformly(mesh, 1)

    # make sure the world doesn't end
    from meshmode.discretization import Discretization
    discr = Discretization(actx, mesh,
                           InterpolatoryQuadratureSimplexGroupFactory(4))
    thaw(discr.nodes(), actx)

    from meshmode.discretization.visualization import make_visualizer
    make_visualizer(actx, discr, 4)
Esempio n. 4
0
    def map_node_coordinate_component(self, expr):
        discr = self.places.get_discretization(expr.dofdesc.geometry,
                                               expr.dofdesc.discr_stage)

        from arraycontext import thaw
        x = discr.nodes()[expr.ambient_axis]
        return thaw(x, self.array_context)
Esempio n. 5
0
def test_chained_full_resample_matrix(actx_factory, ndim, visualize=False):
    from meshmode.discretization.connection.chained import \
        make_full_resample_matrix

    actx = actx_factory()

    discr = create_discretization(actx, ndim, order=2, nelements=12)
    connections = []
    conn = create_refined_connection(actx, discr)
    connections.append(conn)
    conn = create_refined_connection(actx, conn.to_discr)
    connections.append(conn)

    from meshmode.discretization.connection import \
            ChainedDiscretizationConnection
    chained = ChainedDiscretizationConnection(connections)

    def f(x):
        from functools import reduce
        return 0.1 * reduce(lambda x, y: x * actx.np.sin(5 * y), x)

    resample_mat = actx.to_numpy(make_full_resample_matrix(actx, chained))

    x = thaw(connections[0].from_discr.nodes(), actx)
    fx = f(x)
    f1 = resample_mat @ flatten_to_numpy(actx, fx)
    f2 = flatten_to_numpy(actx, chained(fx))
    f3 = flatten_to_numpy(actx, connections[1](connections[0](fx)))

    assert np.allclose(f1, f2)
    assert np.allclose(f2, f3)
Esempio n. 6
0
def main():
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    from meshmode.mesh.generation import (  # noqa
        generate_icosphere, generate_icosahedron, generate_torus)
    #mesh = generate_icosphere(1, order=order)
    mesh = generate_icosahedron(1, order=order)
    #mesh = generate_torus(3, 1, order=order)

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            PolynomialWarpAndBlendGroupFactory

    discr = Discretization(actx, mesh,
                           PolynomialWarpAndBlendGroupFactory(order))

    from meshmode.discretization.visualization import make_visualizer
    vis = make_visualizer(actx, discr, order)

    vis.write_vtk_file("geometry.vtu", [
        ("f", thaw(discr.nodes()[0], actx)),
    ])

    from meshmode.discretization.visualization import \
            write_nodal_adjacency_vtk_file

    write_nodal_adjacency_vtk_file("adjacency.vtu", mesh)
Esempio n. 7
0
def area_element(actx: ArrayContext,
                 dcoll: DiscretizationCollection,
                 dd=None,
                 *,
                 _use_geoderiv_connection=False) -> DOFArray:
    r"""Computes the scale factor used to transform integrals from reference
    to global space.

    This function caches its results.

    :arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value convertible to one.
        Defaults to the base volume discretization.
    :arg _use_geoderiv_connection: If *True*, process returned
        :class:`~meshmode.dof_array.DOFArray`\ s through
        :meth:`~grudge.DiscretizationCollection._base_to_geoderiv_connection`.
        This should be set based on whether the code using the result of this
        function is able to make use of these arrays.  (This is an internal
        argument and not intended for use outside :mod:`grudge`.)
    :returns: a :class:`~meshmode.dof_array.DOFArray` containing the transformed
        volumes for each element.
    """
    if dd is None:
        dd = DD_VOLUME

    @memoize_in(dcoll, (area_element, dd, _use_geoderiv_connection))
    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)

    return thaw(_area_elements(), actx)
Esempio n. 8
0
def test_geometric_factors_regular_refinement(actx_factory, name):
    from grudge.dt_utils import dt_geometric_factors

    actx = actx_factory()

    # {{{ cases

    if name == "interval":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=1)
    elif name == "box2d":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=2)
    elif name == "box3d":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=3)
    else:
        raise ValueError("unknown geometry name: %s" % name)

    # }}}

    min_factors = []
    for resolution in builder.resolutions:
        mesh = builder.get_mesh(resolution, builder.mesh_order)
        dcoll = DiscretizationCollection(actx, mesh, order=builder.order)
        min_factors.append(
            actx.to_numpy(
                op.nodal_min(dcoll, "vol",
                             thaw(dt_geometric_factors(dcoll), actx))))

    # Resolution is doubled each refinement, so the ratio of consecutive
    # geometric factors should satisfy: gfi+1 / gfi = 2
    min_factors = np.asarray(min_factors)
    ratios = min_factors[:-1] / min_factors[1:]
    assert np.all(np.isclose(ratios, 2))
Esempio n. 9
0
    def map_num_reference_derivative(self, expr):
        from pytential import bind, sym
        rec_operand = self.rec(expr.operand)

        assert isinstance(rec_operand, np.ndarray)
        if self.is_kind_matrix(rec_operand):
            raise NotImplementedError("derivatives")

        actx = self.array_context
        dofdesc = expr.dofdesc
        op = sym.NumReferenceDerivative(ref_axes=expr.ref_axes,
                                        operand=sym.var("u"),
                                        dofdesc=dofdesc)

        discr = self.places.get_discretization(dofdesc.geometry,
                                               dofdesc.discr_stage)

        template_ary = thaw(discr.nodes()[0], actx)
        rec_operand = unflatten(template_ary, actx.from_numpy(rec_operand),
                                actx)

        return actx.to_numpy(
            flatten(
                bind(self.places, op)(self.array_context, u=rec_operand),
                actx))
Esempio n. 10
0
def evaluate_sphere_eigf(actx, discr, m: int, n: int) -> DOFArray:
    assert discr.ambient_dim == 3

    # {{{ get spherical coordinates

    from arraycontext import thaw
    x, y, z = thaw(discr.nodes(), actx)

    theta = actx.np.arctan2(actx.np.sqrt(x**2 + y**2), z)
    phi = actx.np.arctan2(y, x)

    # }}}

    # {{{ evaluate Y^m_n

    from scipy.special import sph_harm      # pylint: disable=no-name-in-module
    y_mn = []
    for gtheta, gphi in zip(theta, phi):
        result = sph_harm(m, n, actx.to_numpy(gphi), actx.to_numpy(gtheta))

        y_mn.append(actx.from_numpy(result.real.copy()))

    # }}}

    return DOFArray(actx, tuple(y_mn))
Esempio n. 11
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(dcoll.normal(dd), u.int.array_context)

    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)
Esempio n. 12
0
def test_flatten_unflatten(actx_factory):
    actx = actx_factory()

    ambient_dim = 2
    from meshmode.mesh.generation import generate_regular_rect_mesh
    mesh = generate_regular_rect_mesh(a=(-0.5, ) * ambient_dim,
                                      b=(+0.5, ) * ambient_dim,
                                      n=(3, ) * ambient_dim,
                                      order=1)
    discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(3))
    a = np.random.randn(discr.ndofs)

    from meshmode.dof_array import flatten, unflatten
    a_round_trip = actx.to_numpy(
        flatten(unflatten(actx, discr, actx.from_numpy(a))))
    assert np.array_equal(a, a_round_trip)

    from meshmode.dof_array import flatten_to_numpy, unflatten_from_numpy
    a_round_trip = flatten_to_numpy(actx, unflatten_from_numpy(actx, discr, a))
    assert np.array_equal(a, a_round_trip)

    x = thaw(discr.nodes(), actx)
    avg_mass = DOFArray(
        actx,
        tuple([(np.pi + actx.zeros((grp.nelements, 1), a.dtype))
               for grp in discr.groups]))

    c = MyContainer(name="flatten",
                    mass=avg_mass,
                    momentum=make_obj_array([x, x, x]),
                    enthalpy=x)

    from meshmode.dof_array import unflatten_like
    c_round_trip = unflatten_like(actx, flatten(c), c)
    assert flat_norm(c - c_round_trip) < 1.0e-8
Esempio n. 13
0
def test_interpolation(actx_factory, name, source_discr_stage, target_granularity):
    actx = actx_factory()

    nelements = 32
    target_order = 7
    qbx_order = 4

    where = sym.as_dofdesc("test_interpolation")
    from_dd = sym.DOFDescriptor(
            geometry=where.geometry,
            discr_stage=source_discr_stage,
            granularity=sym.GRANULARITY_NODE)
    to_dd = sym.DOFDescriptor(
            geometry=where.geometry,
            discr_stage=sym.QBX_SOURCE_QUAD_STAGE2,
            granularity=target_granularity)

    mesh = mgen.make_curve_mesh(mgen.starfish,
            np.linspace(0.0, 1.0, nelements + 1),
            target_order)
    discr = Discretization(actx, mesh,
            InterpolatoryQuadratureSimplexGroupFactory(target_order))

    from pytential.qbx import QBXLayerPotentialSource
    qbx = QBXLayerPotentialSource(discr,
            fine_order=4 * target_order,
            qbx_order=qbx_order,
            fmm_order=False)

    from pytential import GeometryCollection
    places = GeometryCollection(qbx, auto_where=where)

    sigma_sym = sym.var("sigma")
    op_sym = sym.sin(sym.interp(from_dd, to_dd, sigma_sym))
    bound_op = bind(places, op_sym, auto_where=where)

    def discr_and_nodes(stage):
        density_discr = places.get_discretization(where.geometry, stage)
        return density_discr, actx.to_numpy(
                flatten(density_discr.nodes(), actx)
                ).reshape(density_discr.ambient_dim, -1)

    _, target_nodes = discr_and_nodes(sym.QBX_SOURCE_QUAD_STAGE2)
    source_discr, source_nodes = discr_and_nodes(source_discr_stage)

    sigma_target = np.sin(la.norm(target_nodes, axis=0))
    sigma_dev = unflatten(
            thaw(source_discr.nodes()[0], actx),
            actx.from_numpy(la.norm(source_nodes, axis=0)), actx)
    sigma_target_interp = actx.to_numpy(
            flatten(bound_op(actx, sigma=sigma_dev), actx)
            )

    if name in ("default", "default_explicit", "stage2", "quad"):
        error = la.norm(sigma_target_interp - sigma_target) / la.norm(sigma_target)
        assert error < 1.0e-10
    elif name in ("stage2_center",):
        assert len(sigma_target_interp) == 2 * len(sigma_target)
    else:
        raise ValueError(f"unknown test case name: {name}")
Esempio n. 14
0
 def boundary_solution(discr, btag, gas_model, state_minus, **kwargs):
     actx = state_minus.array_context
     bnd_discr = discr.discr_from_dd(btag)
     nodes = thaw(bnd_discr.nodes(), actx)
     return make_fluid_state(initializer(x_vec=nodes, eos=gas_model.eos,
                                         **kwargs), gas_model,
                             temperature_seed=state_minus.temperature)
Esempio n. 15
0
File: em.py Progetto: 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
Esempio n. 16
0
File: em.py Progetto: 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)
Esempio n. 17
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
Esempio n. 18
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))
Esempio n. 19
0
def flux(dcoll, u_tpair):
    dd = u_tpair.dd
    velocity = np.array([2 * np.pi])
    normal = thaw(dcoll.normal(dd), actx)

    v_dot_n = np.dot(velocity, normal)
    u_upwind = actx.np.where(v_dot_n > 0,
                             u_tpair.int, u_tpair.ext)
    return u_upwind * v_dot_n
Esempio n. 20
0
def test_modal_coefficients_by_projection(actx_factory, quad_group_factory):
    group_cls = SimplexElementGroup
    modal_group_factory = ModalSimplexGroupFactory
    actx = actx_factory()
    order = 10
    m_order = 5

    # Make a regular rectangle mesh
    mesh = mgen.generate_regular_rect_mesh(a=(0, 0),
                                           b=(5, 3),
                                           npoints_per_axis=(10, 6),
                                           order=order,
                                           group_cls=group_cls)

    # Make discretizations
    nodal_disc = Discretization(actx, mesh, quad_group_factory(order))
    modal_disc = Discretization(actx, mesh, modal_group_factory(m_order))

    # Make connections one using quadrature projection
    nodal_to_modal_conn_quad = NodalToModalDiscretizationConnection(
        nodal_disc, modal_disc, allow_approximate_quad=True)

    def f(x):
        return 2 * actx.np.sin(5 * x)

    x_nodal = thaw(nodal_disc.nodes()[0], actx)
    nodal_f = f(x_nodal)

    # Compute modal coefficients we expect to get
    import modepy as mp

    grp, = nodal_disc.groups
    shape = mp.Simplex(grp.dim)
    space = mp.space_for_shape(shape, order=m_order)
    basis = mp.orthonormal_basis_for_space(space, shape)
    quad = grp.quadrature_rule()

    nodal_f_data = actx.to_numpy(nodal_f[0])
    vdm = mp.vandermonde(basis.functions, quad.nodes)
    w_diag = np.diag(quad.weights)

    modal_data = []
    for _, nodal_data in enumerate(nodal_f_data):
        # Compute modal data in each element: V.T * W * nodal_data
        elem_modal_f = np.dot(vdm.T, np.dot(w_diag, nodal_data))
        modal_data.append(elem_modal_f)

    modal_data = actx.from_numpy(np.asarray(modal_data))
    modal_f_expected = DOFArray(actx, data=(modal_data, ))

    # Map nodal coefficients using the quadrature-based projection
    modal_f_computed = nodal_to_modal_conn_quad(nodal_f)

    err = flat_norm(modal_f_expected - modal_f_computed)

    assert err <= 1e-13
Esempio n. 21
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. 22
0
 def map_node_coordinate_component(self, expr):
     discr = self.dcoll.discr_from_dd(expr.dd)
     return thaw(
         discr.nodes(
             # only save volume nodes or boundary nodes
             # (but not nodes for interior face discretizations, which
             # are likely only used once to compute the normals)
             cached=(discr.ambient_dim == discr.dim or expr.dd.
                     is_boundary_or_partition_interface()))[expr.axis],
         self.array_context)
Esempio n. 23
0
    def run(nelements, order):
        discr = create_discretization(actx,
                                      ndim,
                                      nelements=nelements,
                                      order=order,
                                      mesh_name=mesh_name)

        threshold = 1.0
        connections = []
        conn = create_refined_connection(actx, discr, threshold=threshold)
        connections.append(conn)
        if ndim == 2:
            # NOTE: additional refinement makes the 3D meshes explode in size
            conn = create_refined_connection(actx,
                                             conn.to_discr,
                                             threshold=threshold)
            connections.append(conn)
            conn = create_refined_connection(actx,
                                             conn.to_discr,
                                             threshold=threshold)
            connections.append(conn)

        from meshmode.discretization.connection import \
                ChainedDiscretizationConnection
        chained = ChainedDiscretizationConnection(connections)
        from meshmode.discretization.connection import \
                L2ProjectionInverseDiscretizationConnection
        reverse = L2ProjectionInverseDiscretizationConnection(chained)

        # create test vector
        from_nodes = thaw(chained.from_discr.nodes(), actx)
        to_nodes = thaw(chained.to_discr.nodes(), actx)

        from_x = 0
        to_x = 0
        for d in range(ndim):
            from_x = from_x + actx.np.cos(from_nodes[d])**(d + 1)
            to_x = to_x + actx.np.cos(to_nodes[d])**(d + 1)

        from_interp = reverse(to_x)

        return (1.0 / nelements, flat_norm(from_interp - from_x, np.inf) /
                flat_norm(from_x, np.inf))
Esempio n. 24
0
def inverse_surface_metric_derivative_mat(actx: ArrayContext,
                                          dcoll: DiscretizationCollection,
                                          dd=None,
                                          *,
                                          times_area_element=False,
                                          _use_geoderiv_connection=False):
    r"""Computes the matrix of inverse surface metric derivatives, indexed by
    ``(xyz_axis, rst_axis)``. It returns all values of
    :func:`inverse_surface_metric_derivative_mat` in cached matrix form.

    This function caches its results.

    :arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value convertible to one.
        Defaults to the base volume discretization.
    :arg times_area_element: If *True*, each entry of the matrix is premultiplied
        with the value of :func:`area_element`, reflecting the typical use
        of the matrix in integrals evaluating weak derivatives.
    :arg _use_geoderiv_connection: If *True*, process returned
        :class:`~meshmode.dof_array.DOFArray`\ s through
        :meth:`~grudge.DiscretizationCollection._base_to_geoderiv_connection`.
        This should be set based on whether the code using the result of this
        function is able to make use of these arrays.  (This is an internal
        argument and not intended for use outside :mod:`grudge`.)
    :returns: a :class:`~meshmode.dof_array.DOFArray` containing the
        inverse metric derivatives in per-group arrays of shape
        ``(xyz_dimension, rst_dimension, nelements, ndof)``.
    """
    @memoize_in(dcoll, (inverse_surface_metric_derivative_mat, dd,
                        times_area_element, _use_geoderiv_connection))
    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)

    return thaw(_inv_surf_metric_deriv(), actx)
Esempio n. 25
0
def test_nodal_reductions(actx_factory):
    actx = actx_factory()

    from mesh_data import BoxMeshBuilder
    builder = BoxMeshBuilder(ambient_dim=1)

    mesh = builder.get_mesh(4, builder.mesh_order)
    dcoll = DiscretizationCollection(actx, mesh, order=builder.order)
    x = thaw(dcoll.nodes(), actx)

    def f(x):
        return -actx.np.sin(10 * x[0])

    def g(x):
        return actx.np.cos(2 * x[0])

    def h(x):
        return -actx.np.tan(5 * x[0])

    fields = make_obj_array([f(x), g(x), h(x)])

    f_ref = actx.to_numpy(flatten(fields[0]))
    g_ref = actx.to_numpy(flatten(fields[1]))
    h_ref = actx.to_numpy(flatten(fields[2]))
    concat_fields = np.concatenate([f_ref, g_ref, h_ref])

    for inner_grudge_op, np_op in [(op.nodal_sum, np.sum),
                                   (op.nodal_max, np.max),
                                   (op.nodal_min, np.min)]:

        # FIXME: Remove this once all grudge reductions return device scalars
        def grudge_op(dcoll, dd, vec):
            res = inner_grudge_op(dcoll, dd, vec)

            from numbers import Number
            if not isinstance(res, Number):
                return actx.to_numpy(res)
            else:
                return res

        # Componentwise reduction checks
        assert np.isclose(grudge_op(dcoll, "vol", fields[0]),
                          np_op(f_ref),
                          rtol=1e-13)
        assert np.isclose(grudge_op(dcoll, "vol", fields[1]),
                          np_op(g_ref),
                          rtol=1e-13)
        assert np.isclose(grudge_op(dcoll, "vol", fields[2]),
                          np_op(h_ref),
                          rtol=1e-13)

        # Test nodal reductions work on object arrays
        assert np.isclose(grudge_op(dcoll, "vol", fields),
                          np_op(concat_fields),
                          rtol=1e-13)
Esempio n. 26
0
def partition_by_nodes(
        actx: PyOpenCLArrayContext,
        discr: Discretization,
        *,
        tree_kind: Optional[str] = "adaptive-level-restricted",
        max_particles_in_box: Optional[int] = None) -> BlockIndexRanges:
    """Generate equally sized ranges of nodes. The partition is created at the
    lowest level of granularity, i.e. nodes. This results in balanced ranges
    of points, but will split elements across different ranges.

    :arg tree_kind: if not *None*, it is passed to :class:`boxtree.TreeBuilder`.
    :arg max_particles_in_box: passed to :class:`boxtree.TreeBuilder`.
    """

    if max_particles_in_box is None:
        # FIXME: this is just an arbitrary value
        max_particles_in_box = 32

    if tree_kind is not None:
        from boxtree import box_flags_enum
        from boxtree import TreeBuilder

        builder = TreeBuilder(actx.context)

        from arraycontext import thaw
        tree, _ = builder(actx.queue,
                          particles=flatten(thaw(discr.nodes(), actx),
                                            actx,
                                            leaf_class=DOFArray),
                          max_particles_in_box=max_particles_in_box,
                          kind=tree_kind)

        tree = tree.get(actx.queue)
        leaf_boxes, = (tree.box_flags
                       & box_flags_enum.HAS_CHILDREN == 0).nonzero()

        indices = np.empty(len(leaf_boxes), dtype=object)
        ranges = None

        for i, ibox in enumerate(leaf_boxes):
            box_start = tree.box_source_starts[ibox]
            box_end = box_start + tree.box_source_counts_cumul[ibox]
            indices[i] = tree.user_source_ids[box_start:box_end]
    else:
        if discr.ambient_dim != 2 and discr.dim == 1:
            raise ValueError("only curves are supported for 'tree_kind=None'")

        nblocks = max(discr.ndofs // max_particles_in_box, 2)
        indices = np.arange(0, discr.ndofs, dtype=np.int64)
        ranges = np.linspace(0, discr.ndofs, nblocks + 1, dtype=np.int64)
        assert ranges[-1] == discr.ndofs

    from pytential.linalg import make_block_index_from_array
    return make_block_index_from_array(indices, ranges=ranges)
Esempio n. 27
0
def test_sanity_qhull_nd(actx_factory, dim, order):
    pytest.importorskip("scipy")

    logging.basicConfig(level=logging.INFO)
    actx = actx_factory()

    from scipy.spatial import Delaunay  # pylint: disable=no-name-in-module
    verts = np.random.rand(1000, dim)
    dtri = Delaunay(verts)

    # pylint: disable=no-member
    from meshmode.mesh.io import from_vertices_and_simplices
    mesh = from_vertices_and_simplices(dtri.points.T,
                                       dtri.simplices,
                                       fix_orientation=True)

    from meshmode.discretization import Discretization
    low_discr = Discretization(actx, mesh,
                               PolynomialEquidistantSimplexGroupFactory(order))
    high_discr = Discretization(
        actx, mesh, PolynomialEquidistantSimplexGroupFactory(order + 1))

    from meshmode.discretization.connection import make_same_mesh_connection
    cnx = make_same_mesh_connection(actx, high_discr, low_discr)

    def f(x):
        return 0.1 * actx.np.sin(x)

    x_low = thaw(low_discr.nodes()[0], actx)
    f_low = f(x_low)

    x_high = thaw(high_discr.nodes()[0], actx)
    f_high_ref = f(x_high)

    f_high_num = cnx(f_low)

    err = (flat_norm(f_high_ref - f_high_num, np.inf) /
           flat_norm(f_high_ref, np.inf))

    print(err)
    assert err < 1e-2
Esempio n. 28
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. 29
0
def parametrization_derivative(actx, discr):
    thawed_nodes = thaw(discr.nodes(), actx)

    from meshmode.discretization import num_reference_derivative
    result = np.zeros((discr.ambient_dim, discr.dim), dtype=object)
    for iambient in range(discr.ambient_dim):
        for idim in range(discr.dim):
            result[iambient,
                   idim] = num_reference_derivative(discr, (idim, ),
                                                    thawed_nodes[iambient])

    return result
Esempio n. 30
0
def evaluate_circle_eigf(actx, discr, k: int) -> np.ndarray:
    assert discr.ambient_dim == 2

    # {{{ get polar coordinates

    from arraycontext import thaw
    x, y = thaw(discr.nodes(), actx)
    theta = actx.np.arctan2(y, x)

    # }}}

    return actx.np.exp(-1j * k * theta)