Exemplo n.º 1
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(actx, connections[0].from_discr.nodes())
    fx = f(x)
    f1 = resample_mat @ actx.to_numpy(flatten(fx))
    f2 = actx.to_numpy(flatten(chained(fx)))
    f3 = actx.to_numpy(flatten(connections[1](connections[0](fx))))

    assert np.allclose(f1, f2)
    assert np.allclose(f2, f3)
Exemplo n.º 2
0
def test_chained_connection(actx_factory, ndim, visualize=False):
    actx = actx_factory()

    discr = create_discretization(actx, ndim, nelements=10)
    connections = []
    conn = create_refined_connection(actx, discr, threshold=np.inf)
    connections.append(conn)
    conn = create_refined_connection(actx, conn.to_discr, threshold=np.inf)
    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)

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

    assert actx.np.linalg.norm(f1 - f2,
                               np.inf) / actx.np.linalg.norm(f2) < 1e-11
Exemplo n.º 3
0
def test_chained_connection(ctx_factory, ndim, visualize=False):
    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    discr = create_discretization(queue, ndim,
                                  nelements=10)
    connections = []
    conn = create_refined_connection(queue, discr, threshold=np.inf)
    connections.append(conn)
    conn = create_refined_connection(queue, conn.to_discr, threshold=np.inf)
    connections.append(conn)

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

    def f(x):
        from six.moves import reduce
        return 0.1 * reduce(lambda x, y: x * cl.clmath.sin(5 * y), x)

    x = connections[0].from_discr.nodes().with_queue(queue)
    fx = f(x)
    f1 = chained(queue, fx).get(queue)
    f2 = connections[1](queue, connections[0](queue, fx)).get(queue)

    assert np.allclose(f1, f2)
Exemplo n.º 4
0
def test_chained_full_resample_matrix(ctx_factory, ndim, visualize=False):
    from meshmode.discretization.connection.chained import \
        make_full_resample_matrix

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    discr = create_discretization(queue, ndim)
    connections = []
    conn = create_refined_connection(queue, discr)
    connections.append(conn)
    conn = create_refined_connection(queue, conn.to_discr)
    connections.append(conn)

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

    def f(x):
        from six.moves import reduce
        return 0.1 * reduce(lambda x, y: x * cl.clmath.sin(5 * y), x)

    resample_mat = make_full_resample_matrix(queue, chained).get(queue)

    x = connections[0].from_discr.nodes().with_queue(queue)
    fx = f(x)
    f1 = np.dot(resample_mat, fx.get(queue))
    f2 = chained(queue, fx).get(queue)
    f3 = connections[1](queue, connections[0](queue, fx)).get(queue)

    assert np.allclose(f1, f2)
    assert np.allclose(f2, f3)
Exemplo n.º 5
0
def test_chained_batch_table(ctx_factory, ndim, visualize=False):
    from meshmode.discretization.connection.chained import \
        _build_element_lookup_table

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    discr = create_discretization(queue, ndim)
    connections = []
    conn = create_refined_connection(queue, discr)
    connections.append(conn)
    conn = create_refined_connection(queue, conn.to_discr)
    connections.append(conn)

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

    conn = chained.connections[0]
    el_table = _build_element_lookup_table(queue, conn)
    for igrp, grp in enumerate(conn.groups):
        for ibatch, batch in enumerate(grp.batches):
            ifrom = batch.from_element_indices.get(queue)
            jfrom = el_table[igrp][batch.to_element_indices.get(queue)]

            assert np.all(ifrom == jfrom)
        assert np.min(el_table[igrp]) >= 0
Exemplo n.º 6
0
def test_chained_full_resample_matrix(ctx_factory, ndim, visualize=False):
    from meshmode.discretization.connection.chained import \
        make_full_resample_matrix

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)
    actx = PyOpenCLArrayContext(queue)

    discr = create_discretization(actx, ndim)
    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 six.moves 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(actx, connections[0].from_discr.nodes())
    fx = f(x)
    f1 = resample_mat @ actx.to_numpy(flatten(fx))
    f2 = actx.to_numpy(flatten(chained(fx)))
    f3 = actx.to_numpy(flatten(connections[1](connections[0](fx))))

    assert np.allclose(f1, f2)
    assert np.allclose(f2, f3)
Exemplo n.º 7
0
    def resampler(self):
        from meshmode.discretization.connection import \
                ChainedDiscretizationConnection

        conn = self.refined_interp_to_ovsmp_quad_connection

        if self._to_refined_connection is not None:
            return ChainedDiscretizationConnection(
                [self._to_refined_connection, conn])

        return conn
Exemplo n.º 8
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(actx, chained.from_discr.nodes())
        to_nodes = thaw(actx, chained.to_discr.nodes())

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

        from_interp = reverse(to_x)

        return (1.0 / nelements,
                actx.np.linalg.norm(from_interp - from_x, np.inf) /
                actx.np.linalg.norm(from_x, np.inf))
Exemplo n.º 9
0
    def run(nelements, order):
        discr = create_discretization(queue, ndim,
            nelements=nelements,
            order=order,
            mesh_name=mesh_name)

        threshold = 1.0
        connections = []
        conn = create_refined_connection(queue,
                discr, threshold=threshold)
        connections.append(conn)
        if ndim == 2:
            # NOTE: additional refinement makes the 3D meshes explode in size
            conn = create_refined_connection(queue,
                    conn.to_discr, threshold=threshold)
            connections.append(conn)
            conn = create_refined_connection(queue,
                    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 = chained.from_discr.nodes().with_queue(queue)
        to_nodes = chained.to_discr.nodes().with_queue(queue)

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

        from_interp = reverse(queue, to_x)

        from_interp = from_interp.get(queue)
        from_x = from_x.get(queue)

        return 1.0 / nelements, la.norm(from_interp - from_x) / la.norm(from_x)
Exemplo n.º 10
0
    def get_qbx(self, **kwargs):
        """
            Return a :class:`QBXLayerPotentialSource` to bind
            to an operator
        """
        qbx = QBXLayerPotentialSource(self._discr, **kwargs)

        # {{{ If refining, refine and store connection (possibly composed with bdy
        #     connection
        if self._refine:
            self._refine = False
            from meshmode.discretization.connection import \
                ChainedDiscretizationConnection

            qbx, refinement_connection = qbx.with_refinement()
            if self._connection:
                connections = [self._connection, refinement_connection]
                self._connection = ChainedDiscretizationConnection(connections)
            else:
                self._connection = refinement_connection
        # }}}

        return qbx
Exemplo n.º 11
0
def _refine_qbx_stage2(lpot_source,
                       stage1_density_discr,
                       wrangler,
                       group_factory,
                       expansion_disturbance_tolerance=None,
                       force_stage2_uniform_refinement_rounds=None,
                       maxiter=None,
                       debug=None,
                       visualize=False):
    from meshmode.discretization.connection import ChainedDiscretizationConnection
    if lpot_source._disable_refinement:
        return stage1_density_discr, ChainedDiscretizationConnection(
            [], from_discr=stage1_density_discr)

    from meshmode.mesh.refinement import RefinerWithoutAdjacency
    refiner = RefinerWithoutAdjacency(stage1_density_discr.mesh)

    # TODO: Stop doing redundant checks by avoiding panels which no longer need
    # refinement.

    connections = []
    violated_criteria = []
    iter_violated_criteria = ["start"]
    niter = 0

    stage2_density_discr = stage1_density_discr
    while iter_violated_criteria:
        iter_violated_criteria = []
        niter += 1

        if niter > maxiter:
            _warn_max_iterations(violated_criteria,
                                 expansion_disturbance_tolerance)
            break

        places = _make_temporary_collection(
            lpot_source,
            stage1_density_discr=stage1_density_discr,
            stage2_density_discr=stage2_density_discr)

        # Build tree and auxiliary data.
        # FIXME: The tree should not have to be rebuilt at each iteration.
        tree = wrangler.build_tree(places,
                                   sources_list=[places.auto_source.geometry],
                                   use_stage2_discr=True)
        peer_lists = wrangler.find_peer_lists(tree)
        refine_flags = make_empty_refine_flags(wrangler.queue,
                                               stage2_density_discr)

        has_insufficient_quad_resolution = \
                wrangler.check_sufficient_source_quadrature_resolution(
                        stage2_density_discr, tree, peer_lists, refine_flags,
                        debug)
        if has_insufficient_quad_resolution:
            iter_violated_criteria.append("insufficient quadrature resolution")
            _visualize_refinement(wrangler.queue,
                                  stage2_density_discr,
                                  niter,
                                  2,
                                  "quad-resolution",
                                  refine_flags,
                                  visualize=visualize)

        if iter_violated_criteria:
            violated_criteria.append(" and ".join(iter_violated_criteria))

            conn = wrangler.refine(stage2_density_discr, refiner, refine_flags,
                                   group_factory, debug)
            stage2_density_discr = conn.to_discr
            connections.append(conn)

        del tree
        del refine_flags
        del peer_lists

    for _ in range(force_stage2_uniform_refinement_rounds):
        conn = wrangler.refine(
            stage2_density_discr, refiner,
            np.ones(stage2_density_discr.mesh.nelements, dtype=np.bool),
            group_factory, debug)
        stage2_density_discr = conn.to_discr
        connections.append(conn)

    conn = ChainedDiscretizationConnection(connections,
                                           from_discr=stage1_density_discr)

    return stage2_density_discr, conn
Exemplo n.º 12
0
def test_chained_to_direct(ctx_factory, ndim, chain_type,
                           nelements=128, visualize=False):
    import time
    from meshmode.discretization.connection.chained import \
        flatten_chained_connection

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    discr = create_discretization(queue, ndim, nelements=nelements)
    connections = []
    if chain_type == 1:
        conn = create_refined_connection(queue, discr)
        connections.append(conn)
        conn = create_refined_connection(queue, conn.to_discr)
        connections.append(conn)
    elif chain_type == 2:
        conn = create_refined_connection(queue, discr)
        connections.append(conn)
        conn = create_refined_connection(queue, conn.to_discr)
        connections.append(conn)
        conn = create_refined_connection(queue, conn.to_discr)
        connections.append(conn)
    elif chain_type == 3 and ndim == 3:
        conn = create_refined_connection(queue, discr, threshold=np.inf)
        connections.append(conn)
        conn = create_face_connection(queue, conn.to_discr)
        connections.append(conn)
    else:
        raise ValueError('unknown test case')

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

    t_start = time.time()
    direct = flatten_chained_connection(queue, chained)
    t_end = time.time()
    if visualize:
        print('[TIME] Flatten: {:.5e}'.format(t_end - t_start))

    if chain_type < 3:
        to_element_indices = np.full(direct.to_discr.mesh.nelements, 0,
                                     dtype=np.int)
        for grp in direct.groups:
            for batch in grp.batches:
                for i in batch.to_element_indices.get(queue):
                    to_element_indices[i] += 1
        assert np.min(to_element_indices) > 0

    def f(x):
        from six.moves import reduce
        return 0.1 * reduce(lambda x, y: x * cl.clmath.sin(5 * y), x)

    x = connections[0].from_discr.nodes().with_queue(queue)
    fx = f(x)

    t_start = time.time()
    f1 = direct(queue, fx).get(queue)
    t_end = time.time()
    if visualize:
        print('[TIME] Direct: {:.5e}'.format(t_end - t_start))

    t_start = time.time()
    f2 = chained(queue, fx).get(queue)
    t_end = time.time()
    if visualize:
        print('[TIME] Chained: {:.5e}'.format(t_end - t_start))

    if visualize and ndim == 2:
        import matplotlib.pyplot as pt

        pt.figure(figsize=(10, 8), dpi=300)
        pt.plot(f1, label='Direct')
        pt.plot(f2, label='Chained')
        pt.ylim([np.min(f2) - 0.1, np.max(f2) + 0.1])
        pt.legend()
        pt.savefig('test_chained_to_direct.png')
        pt.clf()

    assert np.allclose(f1, f2)
Exemplo n.º 13
0
def connection_from_dds(places, from_dd, to_dd):
    """
    :arg places: a :class:`~pytential.symbolic.execution.GeometryCollection`
        or an argument taken by its constructor.
    :arg from_dd: a descriptor for the incoming degrees of freedom. This
        can be a :class:`~pytential.symbolic.primitives.DOFDescriptor`
        or an identifier that can be transformed into one by
        :func:`~pytential.symbolic.primitives.as_dofdesc`.
    :arg to_dd: a descriptor for the outgoing degrees of freedom.

    :return: a :class:`DOFConnection` transporting between the two
        kinds of DOF vectors.
    """

    from pytential import sym
    from_dd = sym.as_dofdesc(from_dd)
    to_dd = sym.as_dofdesc(to_dd)

    from pytential import GeometryCollection
    if not isinstance(places, GeometryCollection):
        places = GeometryCollection(places)

    lpot = places.get_geometry(from_dd.geometry)
    from_discr = places.get_discretization(from_dd.geometry,
                                           from_dd.discr_stage)
    to_discr = places.get_discretization(to_dd.geometry, to_dd.discr_stage)

    if from_dd.geometry != to_dd.geometry:
        raise ValueError("cannot interpolate between different geometries")

    if from_dd.granularity is not sym.GRANULARITY_NODE:
        raise ValueError("can only interpolate from `GRANULARITY_NODE`")

    connections = []
    if from_dd.discr_stage is not to_dd.discr_stage:
        from pytential.qbx import QBXLayerPotentialSource
        if not isinstance(lpot, QBXLayerPotentialSource):
            raise ValueError("can only interpolate on a "
                             "`QBXLayerPotentialSource`")

        if to_dd.discr_stage is not sym.QBX_SOURCE_QUAD_STAGE2:
            # TODO: can probably extend this to project from a QUAD_STAGE2
            # using L2ProjectionInverseDiscretizationConnection
            raise ValueError("can only interpolate to "
                             "`QBX_SOURCE_QUAD_STAGE2`")

        # FIXME: would be nice if these were ordered by themselves
        stage_name_to_index_map = {
            None: 0,
            sym.QBX_SOURCE_STAGE1: 1,
            sym.QBX_SOURCE_STAGE2: 2,
            sym.QBX_SOURCE_QUAD_STAGE2: 3
        }
        stage_index_to_name_map = {
            i: name
            for name, i in stage_name_to_index_map.items()
        }

        from_stage = stage_name_to_index_map[from_dd.discr_stage]
        to_stage = stage_name_to_index_map[to_dd.discr_stage]

        for istage in range(from_stage, to_stage):
            conn = places._get_conn_from_cache(
                from_dd.geometry, stage_index_to_name_map[istage],
                stage_index_to_name_map[istage + 1])
            connections.append(conn)

    if from_dd.granularity is not to_dd.granularity:
        if to_dd.granularity is sym.GRANULARITY_NODE:
            pass
        elif to_dd.granularity is sym.GRANULARITY_CENTER:
            connections.append(CenterGranularityConnection(to_discr))
        elif to_dd.granularity is sym.GRANULARITY_ELEMENT:
            raise ValueError("Creating a connection to element granularity "
                             "is not allowed. Use Elementwise{Max,Min,Sum}.")
        else:
            raise ValueError(f"invalid to_dd granularity: {to_dd.granularity}")

    if from_dd.granularity is not to_dd.granularity:
        conn = DOFConnection(connections, from_dd=from_dd, to_dd=to_dd)
    else:
        from meshmode.discretization.connection import \
                ChainedDiscretizationConnection
        conn = ChainedDiscretizationConnection(connections,
                                               from_discr=from_discr)

    return conn
Exemplo n.º 14
0
    def connection_from_dds(self, from_dd, to_dd):
        from_dd = sym.as_dofdesc(from_dd)
        to_dd = sym.as_dofdesc(to_dd)

        to_qtag = to_dd.quadrature_tag

        if (not from_dd.is_volume()
                and from_dd.quadrature_tag == to_dd.quadrature_tag
                and to_dd.domain_tag is sym.FACE_RESTR_ALL):
            faces_conn = self.connection_from_dds(
                sym.DOFDesc("vol"), sym.DOFDesc(from_dd.domain_tag))

            from meshmode.discretization.connection import \
                    make_face_to_all_faces_embedding

            return make_face_to_all_faces_embedding(
                faces_conn, self.discr_from_dd(to_dd),
                self.discr_from_dd(from_dd))

        # {{{ simplify domain + qtag change into chained

        if (from_dd.domain_tag != to_dd.domain_tag
                and from_dd.quadrature_tag is sym.QTAG_NONE
                and to_dd.quadrature_tag is not sym.QTAG_NONE):

            from meshmode.discretization.connection import \
                    ChainedDiscretizationConnection
            intermediate_dd = sym.DOFDesc(to_dd.domain_tag)
            return ChainedDiscretizationConnection([
                # first change domain
                self.connection_from_dds(from_dd, intermediate_dd),

                # then go to quad grid
                self.connection_from_dds(intermediate_dd, to_dd)
            ])

        # }}}

        # {{{ generic to-quad

        if (from_dd.domain_tag == to_dd.domain_tag
                and from_dd.quadrature_tag is sym.QTAG_NONE
                and to_dd.quadrature_tag is not sym.QTAG_NONE):
            from meshmode.discretization.connection.same_mesh import \
                    make_same_mesh_connection

            return make_same_mesh_connection(self.discr_from_dd(to_dd),
                                             self.discr_from_dd(from_dd))

        # }}}

        if from_dd.quadrature_tag is not sym.QTAG_NONE:
            raise ValueError("cannot interpolate *from* a "
                             "(non-interpolatory) quadrature grid")

        assert to_qtag is sym.QTAG_NONE

        if from_dd.is_volume():
            if to_dd.domain_tag is sym.FACE_RESTR_ALL:
                return self._all_faces_volume_connection()
            if to_dd.domain_tag is sym.FACE_RESTR_INTERIOR:
                return self._interior_faces_connection()
            elif to_dd.is_boundary():
                assert from_dd.quadrature_tag is sym.QTAG_NONE
                return self._boundary_connection(to_dd.domain_tag)
            elif to_dd.is_volume():
                from meshmode.discretization.connection import \
                        make_same_mesh_connection
                to_discr = self._quad_volume_discr(to_dd.quadrature_tag)
                from_discr = self._volume_discr
                return make_same_mesh_connection(to_discr, from_discr)

            else:
                raise ValueError("cannot interpolate from volume to: " +
                                 str(to_dd))

        else:
            raise ValueError("cannot interpolate from: " + str(from_dd))
Exemplo n.º 15
0
def test_chained_to_direct(actx_factory,
                           ndim,
                           chain_type,
                           nelements=128,
                           visualize=False):
    import time
    from meshmode.discretization.connection.chained import \
        flatten_chained_connection

    actx = actx_factory()

    discr = create_discretization(actx, ndim, nelements=nelements)
    connections = []
    if chain_type == 1:
        conn = create_refined_connection(actx, discr)
        connections.append(conn)
        conn = create_refined_connection(actx, conn.to_discr)
        connections.append(conn)
    elif chain_type == 2:
        conn = create_refined_connection(actx, discr)
        connections.append(conn)
        conn = create_refined_connection(actx, conn.to_discr)
        connections.append(conn)
        conn = create_refined_connection(actx, conn.to_discr)
        connections.append(conn)
    elif chain_type == 3 and ndim == 3:
        conn = create_refined_connection(actx, discr, threshold=np.inf)
        connections.append(conn)
        conn = create_face_connection(actx, conn.to_discr)
        connections.append(conn)
    else:
        raise ValueError("unknown test case")

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

    t_start = time.time()
    direct = flatten_chained_connection(actx, chained)
    t_end = time.time()
    if visualize:
        print("[TIME] Flatten: {:.5e}".format(t_end - t_start))

    if chain_type < 3:
        to_element_indices = np.full(direct.to_discr.mesh.nelements,
                                     0,
                                     dtype=np.int64)
        for grp in direct.groups:
            for batch in grp.batches:
                for i in batch.to_element_indices.get(actx.queue):
                    to_element_indices[i] += 1
        assert np.min(to_element_indices) > 0

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

    x = thaw(actx, connections[0].from_discr.nodes())
    fx = f(x)

    t_start = time.time()
    f1 = actx.to_numpy(flatten(direct(fx)))
    t_end = time.time()
    if visualize:
        print("[TIME] Direct: {:.5e}".format(t_end - t_start))

    t_start = time.time()
    f2 = actx.to_numpy(flatten(chained(fx)))
    t_end = time.time()
    if visualize:
        print("[TIME] Chained: {:.5e}".format(t_end - t_start))

    if visualize and ndim == 2:
        import matplotlib.pyplot as pt

        pt.figure(figsize=(10, 8), dpi=300)
        pt.plot(f1, label="Direct")
        pt.plot(f2, label="Chained")
        pt.ylim([np.min(f2) - 0.1, np.max(f2) + 0.1])
        pt.legend()
        pt.savefig("test_chained_to_direct.png")
        pt.clf()

    assert np.allclose(f1, f2)
Exemplo n.º 16
0
    def connection_from_dds(self, from_dd, to_dd):
        """Provides a mapping (connection) from one discretization to
        another, e.g. from the volume to the boundary, or from the
        base to the an overintegrated quadrature discretization, or from
        a nodal representation to a modal representation.

        :arg from_dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value
            convertible to one.
        :arg to_dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value
            convertible to one.
        """
        from_dd = as_dofdesc(from_dd)
        to_dd = as_dofdesc(to_dd)

        to_discr_tag = to_dd.discretization_tag
        from_discr_tag = from_dd.discretization_tag

        # {{{ mapping between modal and nodal representations

        if (from_discr_tag is DISCR_TAG_MODAL
                and to_discr_tag is not DISCR_TAG_MODAL):
            return self._modal_to_nodal_connection(to_dd)

        if (to_discr_tag is DISCR_TAG_MODAL
                and from_discr_tag is not DISCR_TAG_MODAL):
            return self._nodal_to_modal_connection(from_dd)

        # }}}

        assert (to_discr_tag is not DISCR_TAG_MODAL
                and from_discr_tag is not DISCR_TAG_MODAL)

        if (not from_dd.is_volume() and from_discr_tag == to_discr_tag
                and to_dd.domain_tag is FACE_RESTR_ALL):
            faces_conn = self.connection_from_dds(DOFDesc("vol"),
                                                  DOFDesc(from_dd.domain_tag))

            from meshmode.discretization.connection import \
                    make_face_to_all_faces_embedding

            return make_face_to_all_faces_embedding(
                self._setup_actx, faces_conn, self.discr_from_dd(to_dd),
                self.discr_from_dd(from_dd))

        # {{{ simplify domain + discr_tag change into chained

        if (from_dd.domain_tag != to_dd.domain_tag
                and from_discr_tag is DISCR_TAG_BASE
                and to_discr_tag is not DISCR_TAG_BASE):

            from meshmode.discretization.connection import \
                    ChainedDiscretizationConnection
            intermediate_dd = DOFDesc(to_dd.domain_tag)
            return ChainedDiscretizationConnection([
                # first change domain
                self.connection_from_dds(from_dd, intermediate_dd),

                # then go to quad grid
                self.connection_from_dds(intermediate_dd, to_dd)
            ])

        # }}}

        # {{{ generic to-quad

        # DISCR_TAG_MODAL is handled above
        if (from_dd.domain_tag == to_dd.domain_tag
                and from_discr_tag is DISCR_TAG_BASE
                and to_discr_tag is not DISCR_TAG_BASE):

            from meshmode.discretization.connection.same_mesh import \
                    make_same_mesh_connection

            return make_same_mesh_connection(self._setup_actx,
                                             self.discr_from_dd(to_dd),
                                             self.discr_from_dd(from_dd))

        # }}}

        if from_discr_tag is not DISCR_TAG_BASE:
            raise ValueError("cannot interpolate *from* a "
                             "(non-interpolatory) quadrature grid")

        assert to_discr_tag is DISCR_TAG_BASE

        if from_dd.is_volume():
            if to_dd.domain_tag is FACE_RESTR_ALL:
                return self._all_faces_volume_connection()
            if to_dd.domain_tag is FACE_RESTR_INTERIOR:
                return self._interior_faces_connection()
            elif to_dd.is_boundary_or_partition_interface():
                assert from_discr_tag is DISCR_TAG_BASE
                return self._boundary_connection(to_dd.domain_tag.tag)
            elif to_dd.is_volume():
                from meshmode.discretization.connection import \
                        make_same_mesh_connection
                to_discr = self._discr_tag_volume_discr(to_discr_tag)
                from_discr = self._volume_discr
                return make_same_mesh_connection(self._setup_actx, to_discr,
                                                 from_discr)

            else:
                raise ValueError("cannot interpolate from volume to: " +
                                 str(to_dd))

        else:
            raise ValueError("cannot interpolate from: " + str(from_dd))
Exemplo n.º 17
0
def refine_for_global_qbx(lpot_source,
                          wrangler,
                          group_factory,
                          kernel_length_scale=None,
                          force_stage2_uniform_refinement_rounds=None,
                          scaled_max_curvature_threshold=None,
                          debug=None,
                          maxiter=None,
                          visualize=None,
                          expansion_disturbance_tolerance=None,
                          refiner=None):
    """
    Entry point for calling the refiner.

    :arg lpot_source: An instance of :class:`QBXLayerPotentialSource`.

    :arg wrangler: An instance of :class:`RefinerWrangler`.

    :arg group_factory: An instance of
        :class:`meshmode.mesh.discretization.ElementGroupFactory`. Used for
        discretizing the coarse refined mesh.

    :arg kernel_length_scale: The kernel length scale, or *None* if not
        applicable. All panels are refined to below this size.

    :arg maxiter: The maximum number of refiner iterations.

    :returns: A tuple ``(lpot_source, *conn*)`` where ``lpot_source`` is the
        refined layer potential source, and ``conn`` is a
        :class:`meshmode.discretization.connection.DiscretizationConnection`
        going from the original mesh to the refined mesh.
    """

    if maxiter is None:
        maxiter = 10

    if debug is None:
        # FIXME: Set debug=False by default once everything works.
        debug = True

    if expansion_disturbance_tolerance is None:
        expansion_disturbance_tolerance = 0.025

    if force_stage2_uniform_refinement_rounds is None:
        force_stage2_uniform_refinement_rounds = 0

    # TODO: Stop doing redundant checks by avoiding panels which no longer need
    # refinement.

    from meshmode.mesh.refinement import RefinerWithoutAdjacency
    from meshmode.discretization.connection import (
        ChainedDiscretizationConnection, make_same_mesh_connection)

    if refiner is not None:
        assert refiner.get_current_mesh() == lpot_source.density_discr.mesh
    else:
        # We may be handed a mesh that's already non-conforming, we don't rely
        # on adjacency, and the no-adjacency refiner is faster.
        refiner = RefinerWithoutAdjacency(lpot_source.density_discr.mesh)

    connections = []

    # {{{ first stage refinement

    def visualize_refinement(niter, stage_nr, stage_name, flags):
        if not visualize:
            return

        if stage_nr == 1:
            discr = lpot_source.density_discr
        elif stage_nr == 2:
            discr = lpot_source.stage2_density_discr
        else:
            raise ValueError("unexpected stage number")

        flags = flags.get()
        logger.info("for stage %s: splitting %d/%d stage-%d elements",
                    stage_name, np.sum(flags), discr.mesh.nelements, stage_nr)

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(wrangler.queue, discr, 3)

        assert len(flags) == discr.mesh.nelements

        flags = flags.astype(np.bool)
        nodes_flags = np.zeros(discr.nnodes)
        for grp in discr.groups:
            meg = grp.mesh_el_group
            grp.view(nodes_flags)[flags[meg.element_nr_base:meg.nelements +
                                        meg.element_nr_base]] = 1

        nodes_flags = cl.array.to_device(wrangler.queue, nodes_flags)
        vis_data = [
            ("refine_flags", nodes_flags),
        ]

        if 0:
            from pytential import sym, bind
            bdry_normals = bind(discr, sym.normal(discr.ambient_dim))(
                wrangler.queue).as_vector(dtype=object)
            vis_data.append(("bdry_normals", bdry_normals), )

        vis.write_vtk_file("refinement-%s-%03d.vtu" % (stage_name, niter),
                           vis_data)

    def warn_max_iterations():
        from warnings import warn
        warn(
            "QBX layer potential source refiner did not terminate "
            "after %d iterations (the maximum). "
            "You may pass 'visualize=True' to with_refinement() "
            "to see what area of the geometry is causing trouble. "
            "If the issue is disturbance of expansion disks, you may "
            "pass a slightly increased value (currently: %g) for "
            "_expansion_disturbance_tolerance in with_refinement(). "
            "As a last resort, "
            "you may use Python's warning filtering mechanism to "
            "not treat this warning as an error. "
            "The criteria triggering refinement in each iteration "
            "were: %s. " %
            (len(violated_criteria), expansion_disturbance_tolerance,
             ", ".join("%d: %s" % (i + 1, vc_text)
                       for i, vc_text in enumerate(violated_criteria))),
            RefinerNotConvergedWarning)

    violated_criteria = []
    iter_violated_criteria = ["start"]

    niter = 0

    while iter_violated_criteria:
        iter_violated_criteria = []
        niter += 1

        if niter > maxiter:
            warn_max_iterations()
            break

        refine_flags = make_empty_refine_flags(wrangler.queue, lpot_source)

        if kernel_length_scale is not None:
            with ProcessLogger(
                    logger,
                    "checking kernel length scale to panel size ratio"):

                from pytential import bind, sym
                quad_resolution = bind(
                    lpot_source,
                    sym._quad_resolution(lpot_source.ambient_dim,
                                         dofdesc=sym.GRANULARITY_ELEMENT))(
                                             wrangler.queue)

                violates_kernel_length_scale = \
                        wrangler.check_element_prop_threshold(
                                element_property=quad_resolution,
                                threshold=kernel_length_scale,
                                refine_flags=refine_flags, debug=debug)

                if violates_kernel_length_scale:
                    iter_violated_criteria.append("kernel length scale")
                    visualize_refinement(niter, 1, "kernel-length-scale",
                                         refine_flags)

        if scaled_max_curvature_threshold is not None:
            with ProcessLogger(logger,
                               "checking scaled max curvature threshold"):
                from pytential import sym, bind
                scaled_max_curv = bind(
                    lpot_source,
                    sym.ElementwiseMax(
                        sym._scaled_max_curvature(lpot_source.ambient_dim),
                        dofdesc=sym.GRANULARITY_ELEMENT))(wrangler.queue)

                violates_scaled_max_curv = \
                        wrangler.check_element_prop_threshold(
                                element_property=scaled_max_curv,
                                threshold=scaled_max_curvature_threshold,
                                refine_flags=refine_flags, debug=debug)

                if violates_scaled_max_curv:
                    iter_violated_criteria.append("curvature")
                    visualize_refinement(niter, 1, "curvature", refine_flags)

        if not iter_violated_criteria:
            # Only start building trees once the simple length-based criteria
            # are happy.

            # Build tree and auxiliary data.
            # FIXME: The tree should not have to be rebuilt at each iteration.
            tree = wrangler.build_tree(lpot_source)
            peer_lists = wrangler.find_peer_lists(tree)

            has_disturbed_expansions = \
                    wrangler.check_expansion_disks_undisturbed_by_sources(
                            lpot_source, tree, peer_lists,
                            expansion_disturbance_tolerance,
                            refine_flags, debug)
            if has_disturbed_expansions:
                iter_violated_criteria.append("disturbed expansions")
                visualize_refinement(niter, 1, "disturbed-expansions",
                                     refine_flags)

            del tree
            del peer_lists

        if iter_violated_criteria:
            violated_criteria.append(" and ".join(iter_violated_criteria))

            conn = wrangler.refine(lpot_source.density_discr, refiner,
                                   refine_flags, group_factory, debug)
            connections.append(conn)
            lpot_source = lpot_source.copy(density_discr=conn.to_discr)

        del refine_flags

    # }}}

    # {{{ second stage refinement

    iter_violated_criteria = ["start"]
    niter = 0
    fine_connections = []

    stage2_density_discr = lpot_source.density_discr

    while iter_violated_criteria:
        iter_violated_criteria = []
        niter += 1

        if niter > maxiter:
            warn_max_iterations()
            break

        # Build tree and auxiliary data.
        # FIXME: The tree should not have to be rebuilt at each iteration.
        tree = wrangler.build_tree(lpot_source, use_stage2_discr=True)
        peer_lists = wrangler.find_peer_lists(tree)
        refine_flags = make_empty_refine_flags(wrangler.queue,
                                               lpot_source,
                                               use_stage2_discr=True)

        has_insufficient_quad_res = \
                wrangler.check_sufficient_source_quadrature_resolution(
                        lpot_source, tree, peer_lists, refine_flags, debug)
        if has_insufficient_quad_res:
            iter_violated_criteria.append("insufficient quadrature resolution")
            visualize_refinement(niter, 2, "quad-resolution", refine_flags)

        if iter_violated_criteria:
            violated_criteria.append(" and ".join(iter_violated_criteria))

            conn = wrangler.refine(stage2_density_discr, refiner, refine_flags,
                                   group_factory, debug)
            stage2_density_discr = conn.to_discr
            fine_connections.append(conn)
            lpot_source = lpot_source.copy(
                to_refined_connection=ChainedDiscretizationConnection(
                    fine_connections))

        del tree
        del refine_flags
        del peer_lists

    for round in range(force_stage2_uniform_refinement_rounds):
        conn = wrangler.refine(
            stage2_density_discr, refiner,
            np.ones(stage2_density_discr.mesh.nelements, dtype=np.bool),
            group_factory, debug)
        stage2_density_discr = conn.to_discr
        fine_connections.append(conn)
        lpot_source = lpot_source.copy(
            to_refined_connection=ChainedDiscretizationConnection(
                fine_connections))

    # }}}

    lpot_source = lpot_source.copy(debug=debug, _refined_for_global_qbx=True)

    if len(connections) == 0:
        # FIXME: This is inefficient
        connection = make_same_mesh_connection(lpot_source.density_discr,
                                               lpot_source.density_discr)
    else:
        connection = ChainedDiscretizationConnection(connections)

    return lpot_source, connection
Exemplo n.º 18
0
def _refine_qbx_stage1(lpot_source,
                       density_discr,
                       wrangler,
                       group_factory,
                       kernel_length_scale=None,
                       scaled_max_curvature_threshold=None,
                       expansion_disturbance_tolerance=None,
                       maxiter=None,
                       debug=None,
                       visualize=False):
    from pytential import bind, sym
    from meshmode.discretization.connection import ChainedDiscretizationConnection
    if lpot_source._disable_refinement:
        return density_discr, ChainedDiscretizationConnection(
            [], from_discr=density_discr)

    from meshmode.mesh.refinement import RefinerWithoutAdjacency
    refiner = RefinerWithoutAdjacency(density_discr.mesh)

    # TODO: Stop doing redundant checks by avoiding panels which no longer need
    # refinement.

    connections = []
    violated_criteria = []
    iter_violated_criteria = ["start"]
    niter = 0

    actx = wrangler.array_context

    stage1_density_discr = density_discr
    while iter_violated_criteria:
        iter_violated_criteria = []
        niter += 1

        if niter > maxiter:
            _warn_max_iterations(violated_criteria,
                                 expansion_disturbance_tolerance)
            break

        refine_flags = make_empty_refine_flags(wrangler.queue,
                                               stage1_density_discr)

        if kernel_length_scale is not None:
            with ProcessLogger(
                    logger,
                    "checking kernel length scale to panel size ratio"):

                quad_resolution = bind(
                    stage1_density_discr,
                    sym._quad_resolution(
                        stage1_density_discr.ambient_dim,
                        dofdesc=sym.GRANULARITY_ELEMENT))(actx)

                violates_kernel_length_scale = \
                        wrangler.check_element_prop_threshold(
                                element_property=quad_resolution,
                                threshold=kernel_length_scale,
                                refine_flags=refine_flags, debug=debug)

                if violates_kernel_length_scale:
                    iter_violated_criteria.append("kernel length scale")
                    _visualize_refinement(actx,
                                          stage1_density_discr,
                                          niter,
                                          1,
                                          "kernel-length-scale",
                                          refine_flags,
                                          visualize=visualize)

        if scaled_max_curvature_threshold is not None:
            with ProcessLogger(logger,
                               "checking scaled max curvature threshold"):
                scaled_max_curv = bind(
                    stage1_density_discr,
                    sym.ElementwiseMax(sym._scaled_max_curvature(
                        stage1_density_discr.ambient_dim),
                                       dofdesc=sym.GRANULARITY_ELEMENT))(actx)

                violates_scaled_max_curv = \
                        wrangler.check_element_prop_threshold(
                                element_property=scaled_max_curv,
                                threshold=scaled_max_curvature_threshold,
                                refine_flags=refine_flags, debug=debug)

                if violates_scaled_max_curv:
                    iter_violated_criteria.append("curvature")
                    _visualize_refinement(wrangler.queue,
                                          stage1_density_discr,
                                          niter,
                                          1,
                                          "curvature",
                                          refine_flags,
                                          visualize=visualize)

        if not iter_violated_criteria:
            # Only start building trees once the simple length-based criteria
            # are happy.
            places = _make_temporary_collection(
                lpot_source, stage1_density_discr=stage1_density_discr)

            # Build tree and auxiliary data.
            # FIXME: The tree should not have to be rebuilt at each iteration.
            tree = wrangler.build_tree(
                places, sources_list=[places.auto_source.geometry])
            peer_lists = wrangler.find_peer_lists(tree)

            has_disturbed_expansions = \
                    wrangler.check_expansion_disks_undisturbed_by_sources(
                            stage1_density_discr, tree, peer_lists,
                            expansion_disturbance_tolerance,
                            refine_flags, debug)
            if has_disturbed_expansions:
                iter_violated_criteria.append("disturbed expansions")
                _visualize_refinement(wrangler.queue,
                                      stage1_density_discr,
                                      niter,
                                      1,
                                      "disturbed-expansions",
                                      refine_flags,
                                      visualize=visualize)

            del tree
            del peer_lists

        if iter_violated_criteria:
            violated_criteria.append(" and ".join(iter_violated_criteria))

            conn = wrangler.refine(stage1_density_discr, refiner, refine_flags,
                                   group_factory, debug)
            stage1_density_discr = conn.to_discr
            connections.append(conn)

        del refine_flags

    conn = ChainedDiscretizationConnection(connections,
                                           from_discr=density_discr)

    return stage1_density_discr, conn