Esempio n. 1
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
Esempio n. 2
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