Example #1
0
    def check_sufficient_source_quadrature_resolution(self,
                                                      stage2_density_discr,
                                                      tree,
                                                      peer_lists,
                                                      refine_flags,
                                                      debug,
                                                      wait_for=None):
        actx = self.array_context

        # Avoid generating too many kernels.
        from pytools import div_ceil
        max_levels = MAX_LEVELS_INCREMENT * div_ceil(tree.nlevels,
                                                     MAX_LEVELS_INCREMENT)

        knl = self.code_container.sufficient_source_quadrature_resolution_checker(
            tree.dimensions, tree.coord_dtype, tree.box_id_dtype,
            peer_lists.peer_list_starts.dtype, tree.particle_id_dtype,
            max_levels)
        if debug:
            nelements_to_refine_prev = actx.to_numpy(
                actx.np.sum(refine_flags)).item()

        found_element_to_refine = actx.zeros(1, dtype=np.int32)
        found_element_to_refine.finish()

        from pytential import bind, sym
        dd = sym.as_dofdesc(sym.GRANULARITY_ELEMENT).to_stage2()
        source_danger_zone_radii_by_element = flatten(
            bind(
                stage2_density_discr,
                sym._source_danger_zone_radii(stage2_density_discr.ambient_dim,
                                              dofdesc=dd))(self.array_context),
            self.array_context)
        unwrap_args = AreaQueryElementwiseTemplate.unwrap_args

        evt = knl(*unwrap_args(
            tree, peer_lists, tree.box_to_qbx_center_starts,
            tree.box_to_qbx_center_lists, tree.qbx_element_to_source_starts,
            tree.qbx_user_source_slice.start, tree.qbx_user_center_slice.start,
            tree.sorted_target_ids, source_danger_zone_radii_by_element,
            tree.nqbxelements, refine_flags, found_element_to_refine,
            *tree.sources),
                  range=slice(tree.nqbxsources),
                  queue=actx.queue,
                  wait_for=wait_for)

        import pyopencl as cl
        cl.wait_for_events([evt])

        if debug:
            nelements_to_refine = actx.to_numpy(
                actx.np.sum(refine_flags)).item()
            if nelements_to_refine > nelements_to_refine_prev:
                logger.debug("refiner: found %d element(s) to refine",
                             nelements_to_refine - nelements_to_refine_prev)

        return actx.to_numpy(found_element_to_refine)[0] == 1
Example #2
0
    def check_sufficient_source_quadrature_resolution(
            self, lpot_source, tree, peer_lists, refine_flags, debug,
            wait_for=None):

        # Avoid generating too many kernels.
        from pytools import div_ceil
        max_levels = MAX_LEVELS_INCREMENT * div_ceil(
                tree.nlevels, MAX_LEVELS_INCREMENT)

        knl = self.code_container.sufficient_source_quadrature_resolution_checker(
                tree.dimensions,
                tree.coord_dtype, tree.box_id_dtype,
                peer_lists.peer_list_starts.dtype,
                tree.particle_id_dtype,
                max_levels)
        if debug:
            npanels_to_refine_prev = cl.array.sum(refine_flags).get()

        found_panel_to_refine = cl.array.zeros(self.queue, 1, np.int32)
        found_panel_to_refine.finish()

        from pytential import bind, sym
        source_danger_zone_radii_by_panel = bind(lpot_source,
                sym._source_danger_zone_radii(
                    lpot_source.ambient_dim,
                    dofdesc=sym.GRANULARITY_ELEMENT))(self.queue)
        unwrap_args = AreaQueryElementwiseTemplate.unwrap_args

        evt = knl(
            *unwrap_args(
                tree, peer_lists,
                tree.box_to_qbx_center_starts,
                tree.box_to_qbx_center_lists,
                tree.qbx_panel_to_source_starts,
                tree.qbx_user_source_slice.start,
                tree.qbx_user_center_slice.start,
                tree.sorted_target_ids,
                source_danger_zone_radii_by_panel,
                tree.nqbxpanels,
                refine_flags,
                found_panel_to_refine,
                *tree.sources),
            range=slice(tree.nqbxsources),
            queue=self.queue,
            wait_for=wait_for)

        cl.wait_for_events([evt])

        if debug:
            npanels_to_refine = cl.array.sum(refine_flags).get()
            if npanels_to_refine > npanels_to_refine_prev:
                logger.debug("refiner: found {} panel(s) to refine".format(
                    npanels_to_refine - npanels_to_refine_prev))

        return found_panel_to_refine.get()[0] == 1
Example #3
0
def run_source_refinement_test(ctx_factory,
                               mesh,
                               order,
                               helmholtz_k=None,
                               visualize=False):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    # {{{ initial geometry

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import (
        InterpolatoryQuadratureSimplexGroupFactory)
    discr = Discretization(actx, mesh,
                           InterpolatoryQuadratureSimplexGroupFactory(order))

    lpot_source = QBXLayerPotentialSource(
        discr,
        qbx_order=order,  # not used in refinement
        fine_order=order)
    places = GeometryCollection(lpot_source)

    # }}}

    # {{{ refined geometry

    kernel_length_scale = 5 / helmholtz_k if helmholtz_k else None
    expansion_disturbance_tolerance = 0.025

    from pytential.qbx.refinement import refine_geometry_collection
    places = refine_geometry_collection(
        places,
        kernel_length_scale=kernel_length_scale,
        expansion_disturbance_tolerance=expansion_disturbance_tolerance,
        visualize=visualize)

    # }}}

    dd = places.auto_source
    stage1_density_discr = places.get_discretization(dd.geometry)
    from meshmode.dof_array import thaw

    stage1_density_nodes = dof_array_to_numpy(
        actx, thaw(actx, stage1_density_discr.nodes()))

    quad_stage2_density_discr = places.get_discretization(
        dd.geometry, sym.QBX_SOURCE_QUAD_STAGE2)
    quad_stage2_density_nodes = dof_array_to_numpy(
        actx, thaw(actx, quad_stage2_density_discr.nodes()))

    int_centers = dof_array_to_numpy(
        actx,
        bind(places, sym.expansion_centers(lpot_source.ambient_dim, -1))(actx))
    ext_centers = dof_array_to_numpy(
        actx,
        bind(places, sym.expansion_centers(lpot_source.ambient_dim, +1))(actx))
    expansion_radii = dof_array_to_numpy(
        actx,
        bind(places, sym.expansion_radii(lpot_source.ambient_dim))(actx))

    dd = dd.copy(granularity=sym.GRANULARITY_ELEMENT)
    source_danger_zone_radii = dof_array_to_numpy(
        actx,
        bind(
            places,
            sym._source_danger_zone_radii(lpot_source.ambient_dim,
                                          dofdesc=dd.to_stage2()))(actx))
    quad_res = dof_array_to_numpy(
        actx,
        bind(places, sym._quad_resolution(lpot_source.ambient_dim,
                                          dofdesc=dd))(actx))

    # {{{ check if satisfying criteria

    def check_disk_undisturbed_by_sources(centers_panel, sources_panel):
        if centers_panel.element_nr == sources_panel.element_nr:
            # Same panel
            return

        my_int_centers = int_centers[:, centers_panel.discr_slice]
        my_ext_centers = ext_centers[:, centers_panel.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = stage1_density_nodes[:, sources_panel.discr_slice]

        # =distance(centers of panel 1, panel 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # A center cannot be closer to another panel than to its originating
        # panel.

        rad = expansion_radii[centers_panel.discr_slice]
        assert (dist >= rad * (1-expansion_disturbance_tolerance)).all(), \
                (dist, rad, centers_panel.element_nr, sources_panel.element_nr)

    def check_sufficient_quadrature_resolution(centers_panel, sources_panel):
        dz_radius = source_danger_zone_radii[sources_panel.element_nr]

        my_int_centers = int_centers[:, centers_panel.discr_slice]
        my_ext_centers = ext_centers[:, centers_panel.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = quad_stage2_density_nodes[:, sources_panel.discr_slice]

        # =distance(centers of panel 1, panel 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # The quadrature contribution from each panel is as accurate
        # as from the center's own source panel.
        assert dist >= dz_radius, \
                (dist, dz_radius, centers_panel.element_nr, sources_panel.element_nr)

    def check_quad_res_to_helmholtz_k_ratio(panel):
        # Check wavenumber to panel size ratio.
        assert quad_res[panel.element_nr] * helmholtz_k <= 5

    for i, panel_1 in enumerate(iter_elements(stage1_density_discr)):
        for panel_2 in iter_elements(stage1_density_discr):
            check_disk_undisturbed_by_sources(panel_1, panel_2)
        for panel_2 in iter_elements(quad_stage2_density_discr):
            check_sufficient_quadrature_resolution(panel_1, panel_2)
        if helmholtz_k is not None:
            check_quad_res_to_helmholtz_k_ratio(panel_1)
Example #4
0
def run_source_refinement_test(ctx_factory, mesh, order, helmholtz_k=None):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import (
        InterpolatoryQuadratureSimplexGroupFactory)

    factory = InterpolatoryQuadratureSimplexGroupFactory(order)

    discr = Discretization(cl_ctx, mesh, factory)

    from pytential.qbx.refinement import (RefinerCodeContainer,
                                          refine_for_global_qbx)

    from pytential.qbx.utils import TreeCodeContainer

    lpot_source = QBXLayerPotentialSource(
        discr,
        qbx_order=order,  # not used in refinement
        fine_order=order)
    del discr

    expansion_disturbance_tolerance = 0.025
    refiner_extra_kwargs = {
        "expansion_disturbance_tolerance": expansion_disturbance_tolerance,
    }
    if helmholtz_k is not None:
        refiner_extra_kwargs["kernel_length_scale"] = 5 / helmholtz_k

    lpot_source, conn = refine_for_global_qbx(
        lpot_source,
        RefinerCodeContainer(cl_ctx,
                             TreeCodeContainer(cl_ctx)).get_wrangler(queue),
        factory, **refiner_extra_kwargs)

    discr_nodes = lpot_source.density_discr.nodes().get(queue)
    fine_discr_nodes = \
            lpot_source.quad_stage2_density_discr.nodes().get(queue)

    int_centers = bind(lpot_source,
                       sym.expansion_centers(lpot_source.ambient_dim,
                                             -1))(queue)
    int_centers = np.array([axis.get(queue) for axis in int_centers])
    ext_centers = bind(lpot_source,
                       sym.expansion_centers(lpot_source.ambient_dim,
                                             +1))(queue)
    ext_centers = np.array([axis.get(queue) for axis in ext_centers])

    expansion_radii = bind(lpot_source,
                           sym.expansion_radii(
                               lpot_source.ambient_dim))(queue).get()
    source_danger_zone_radii = bind(
        lpot_source,
        sym._source_danger_zone_radii(
            lpot_source.ambient_dim,
            dofdesc=sym.GRANULARITY_ELEMENT))(queue).get()

    quad_res = bind(
        lpot_source,
        sym._quad_resolution(lpot_source.ambient_dim,
                             dofdesc=sym.GRANULARITY_ELEMENT))(queue)

    # {{{ check if satisfying criteria

    def check_disk_undisturbed_by_sources(centers_panel, sources_panel):
        if centers_panel.element_nr == sources_panel.element_nr:
            # Same panel
            return

        my_int_centers = int_centers[:, centers_panel.discr_slice]
        my_ext_centers = ext_centers[:, centers_panel.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = discr_nodes[:, sources_panel.discr_slice]

        # =distance(centers of panel 1, panel 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # A center cannot be closer to another panel than to its originating
        # panel.

        rad = expansion_radii[centers_panel.discr_slice]
        assert (dist >= rad * (1-expansion_disturbance_tolerance)).all(), \
                (dist, rad, centers_panel.element_nr, sources_panel.element_nr)

    def check_sufficient_quadrature_resolution(centers_panel, sources_panel):
        dz_radius = source_danger_zone_radii[sources_panel.element_nr]

        my_int_centers = int_centers[:, centers_panel.discr_slice]
        my_ext_centers = ext_centers[:, centers_panel.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = fine_discr_nodes[:, sources_panel.discr_slice]

        # =distance(centers of panel 1, panel 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # The quadrature contribution from each panel is as accurate
        # as from the center's own source panel.
        assert dist >= dz_radius, \
                (dist, dz_radius, centers_panel.element_nr, sources_panel.element_nr)

    def check_quad_res_to_helmholtz_k_ratio(panel):
        # Check wavenumber to panel size ratio.
        assert quad_res[panel.element_nr] * helmholtz_k <= 5

    for i, panel_1 in enumerate(iter_elements(lpot_source.density_discr)):
        for panel_2 in iter_elements(lpot_source.density_discr):
            check_disk_undisturbed_by_sources(panel_1, panel_2)
        for panel_2 in iter_elements(lpot_source.quad_stage2_density_discr):
            check_sufficient_quadrature_resolution(panel_1, panel_2)
        if helmholtz_k is not None:
            check_quad_res_to_helmholtz_k_ratio(panel_1)
Example #5
0
def run_source_refinement_test(actx_factory,
                               mesh,
                               order,
                               helmholtz_k=None,
                               surface_name="surface",
                               visualize=False):
    actx = actx_factory()

    # {{{ initial geometry

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureGroupFactory
    discr = Discretization(actx, mesh,
                           InterpolatoryQuadratureGroupFactory(order))

    lpot_source = QBXLayerPotentialSource(
        discr,
        qbx_order=order,  # not used in refinement
        fine_order=order)
    places = GeometryCollection(lpot_source)

    logger.info("nelements: %d", discr.mesh.nelements)
    logger.info("ndofs: %d", discr.ndofs)

    # }}}

    # {{{ refined geometry

    def _visualize_quad_resolution(_places, dd, suffix):
        if dd.discr_stage is None:
            vis_discr = lpot_source.density_discr
        else:
            vis_discr = _places.get_discretization(dd.geometry, dd.discr_stage)

        stretch = bind(_places,
                       sym._simplex_mapping_max_stretch_factor(
                           _places.ambient_dim, with_elementwise_max=False),
                       auto_where=dd)(actx)

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(actx, vis_discr, order, force_equidistant=True)
        vis.write_vtk_file(
            f"global-qbx-source-refinement-{surface_name}-{order}-{suffix}.vtu",
            [("stretch", stretch)],
            overwrite=True,
            use_high_order=True)

    kernel_length_scale = 5 / helmholtz_k if helmholtz_k else None
    expansion_disturbance_tolerance = 0.025

    from pytential.qbx.refinement import refine_geometry_collection
    places = refine_geometry_collection(
        places,
        kernel_length_scale=kernel_length_scale,
        expansion_disturbance_tolerance=expansion_disturbance_tolerance,
        visualize=False)

    if visualize:
        dd = places.auto_source
        _visualize_quad_resolution(places, dd.copy(discr_stage=None),
                                   "original")
        _visualize_quad_resolution(places, dd.to_stage1(), "stage1")
        _visualize_quad_resolution(places, dd.to_stage2(), "stage2")

    # }}}

    dd = places.auto_source
    ambient_dim = places.ambient_dim
    stage1_density_discr = places.get_discretization(dd.geometry)

    stage1_density_nodes = actx.to_numpy(
        flatten(stage1_density_discr.nodes(), actx)).reshape(ambient_dim, -1)

    quad_stage2_density_discr = places.get_discretization(
        dd.geometry, sym.QBX_SOURCE_QUAD_STAGE2)
    quad_stage2_density_nodes = actx.to_numpy(
        flatten(quad_stage2_density_discr.nodes(),
                actx)).reshape(ambient_dim, -1)

    int_centers = actx.to_numpy(
        flatten(
            bind(places, sym.expansion_centers(ambient_dim, -1))(actx),
            actx)).reshape(ambient_dim, -1)
    ext_centers = actx.to_numpy(
        flatten(
            bind(places, sym.expansion_centers(ambient_dim, +1))(actx),
            actx)).reshape(ambient_dim, -1)
    expansion_radii = actx.to_numpy(
        flatten(bind(places, sym.expansion_radii(ambient_dim))(actx), actx))

    dd = dd.copy(granularity=sym.GRANULARITY_ELEMENT)
    source_danger_zone_radii = actx.to_numpy(
        flatten(
            bind(
                places,
                sym._source_danger_zone_radii(ambient_dim,
                                              dofdesc=dd.to_stage2()))(actx),
            actx))
    quad_res = actx.to_numpy(
        flatten(
            bind(places, sym._quad_resolution(ambient_dim, dofdesc=dd))(actx),
            actx))

    # {{{ check if satisfying criteria

    def check_disk_undisturbed_by_sources(centers_element, sources_element):
        if centers_element.index == sources_element.index:
            # Same element
            return

        my_int_centers = int_centers[:, centers_element.discr_slice]
        my_ext_centers = ext_centers[:, centers_element.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = stage1_density_nodes[:, sources_element.discr_slice]

        # =distance(centers of element 1, element 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # A center cannot be closer to another element than to its originating
        # element.

        rad = expansion_radii[centers_element.discr_slice]
        assert np.all(
            dist >= rad *
            (1 - expansion_disturbance_tolerance)), (dist, rad,
                                                     centers_element.index,
                                                     sources_element.index)

    def check_sufficient_quadrature_resolution(centers_element,
                                               sources_element):
        dz_radius = source_danger_zone_radii[sources_element.index]

        my_int_centers = int_centers[:, centers_element.discr_slice]
        my_ext_centers = ext_centers[:, centers_element.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = quad_stage2_density_nodes[:, sources_element.discr_slice]

        # =distance(centers of element 1, element 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # The quadrature contribution from each element is as accurate
        # as from the center's own source element.
        assert dist >= dz_radius, \
                (dist, dz_radius, centers_element.index, sources_element.index)

    def check_quad_res_to_helmholtz_k_ratio(element):
        # Check wavenumber to element size ratio.
        assert quad_res[element.index] * helmholtz_k <= 5

    for element_1 in iter_elements(stage1_density_discr):
        for element_2 in iter_elements(stage1_density_discr):
            check_disk_undisturbed_by_sources(element_1, element_2)
        for element_2 in iter_elements(quad_stage2_density_discr):
            check_sufficient_quadrature_resolution(element_1, element_2)
        if helmholtz_k is not None:
            check_quad_res_to_helmholtz_k_ratio(element_1)