Ejemplo n.º 1
0
    def __init__(self, queue, geo_data, use_target_specific_qbx):
        from pytential.qbx.utils import ToHostTransferredGeoDataWrapper
        geo_data = ToHostTransferredGeoDataWrapper(queue, geo_data)

        self.geo_data = geo_data
        self.trav = geo_data.traversal()
        self.using_tsqbx = (
                use_target_specific_qbx
                # None means use by default if possible
                or use_target_specific_qbx is None)

        ConstantOneExpansionWrangler.__init__(self, geo_data.tree())
Ejemplo n.º 2
0
    def __init__(self, tree_indep, queue, geo_data, use_target_specific_qbx):
        from pytential.qbx.utils import ToHostTransferredGeoDataWrapper
        geo_data = ToHostTransferredGeoDataWrapper(geo_data)

        self.geo_data = geo_data
        self.trav = geo_data.traversal()
        self.using_tsqbx = (
            use_target_specific_qbx
            # None means use by default if possible
            or use_target_specific_qbx is None)

        super().__init__(tree_indep, geo_data.traversal())
Ejemplo n.º 3
0
    def __init__(self, tree_indep, geo_data, dtype,
            qbx_order, fmm_level_to_order,
            source_extra_kwargs,
            kernel_extra_kwargs,
            _use_target_specific_qbx=None):
        # FMMLib is CPU-only. This wrapper gets the geometry out of
        # OpenCL-land.

        from pytential.qbx.utils import ToHostTransferredGeoDataWrapper
        geo_data = ToHostTransferredGeoDataWrapper(geo_data)

        self.geo_data = geo_data
        self.qbx_order = qbx_order

        if tree_indep.k_name is None:
            helmholtz_k = 0
        else:
            helmholtz_k = kernel_extra_kwargs[tree_indep.k_name]

        dipole_vec = None
        if tree_indep.source_deriv_name is not None:
            with cl.CommandQueue(tree_indep.cl_context) as queue:
                dipole_vec = np.array([
                        d_i.get(queue=queue)
                        for d_i in source_extra_kwargs[
                            tree_indep.source_deriv_name]],
                        order="F")

        def inner_fmm_level_to_nterms(tree, level):
            if helmholtz_k == 0:
                return fmm_level_to_order(
                        LaplaceKernel(tree.dimensions),
                        frozenset(), tree, level)
            else:
                return fmm_level_to_order(
                        HelmholtzKernel(tree.dimensions),
                        frozenset([("k", helmholtz_k)]), tree, level)

        super().__init__(
                tree_indep,
                geo_data.traversal(),

                helmholtz_k=helmholtz_k,
                dipole_vec=dipole_vec,
                dipoles_already_reordered=True,

                fmm_level_to_nterms=inner_fmm_level_to_nterms,
                rotation_data=geo_data)
Ejemplo n.º 4
0
    def qbx_cost_per_box(self, queue, geo_data, kernel, kernel_arguments,
                         calibration_params):
        """This function transfers *geo_data* to host if necessary
        """
        from pytential.qbx.utils import ToHostTransferredGeoDataWrapper
        from pytential.qbx.geometry import QBXFMMGeometryData

        if not isinstance(geo_data, ToHostTransferredGeoDataWrapper):
            assert isinstance(geo_data, QBXFMMGeometryData)
            geo_data = ToHostTransferredGeoDataWrapper(queue, geo_data)

        return AbstractQBXCostModel.qbx_cost_per_box(self, queue, geo_data,
                                                     kernel, kernel_arguments,
                                                     calibration_params)
Ejemplo n.º 5
0
def test_compare_cl_and_py_cost_model(ctx_factory):
    nelements = 3600
    target_order = 16
    fmm_order = 5
    qbx_order = fmm_order

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

    # {{{ Construct geometry

    from meshmode.mesh.generation import make_curve_mesh, starfish
    mesh = make_curve_mesh(starfish, np.linspace(0, 1, nelements), target_order)

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
        InterpolatoryQuadratureSimplexGroupFactory
    pre_density_discr = Discretization(
        actx, mesh,
        InterpolatoryQuadratureSimplexGroupFactory(target_order)
    )

    qbx = QBXLayerPotentialSource(
        pre_density_discr, 4 * target_order,
        qbx_order,
        fmm_order=fmm_order
    )
    places = GeometryCollection(qbx)

    from pytential.qbx.refinement import refine_geometry_collection
    places = refine_geometry_collection(places)

    target_discrs_and_qbx_sides = tuple([(qbx.density_discr, 0)])
    geo_data_dev = qbx.qbx_fmm_geometry_data(
        places, places.auto_source.geometry, target_discrs_and_qbx_sides
    )

    from pytential.qbx.utils import ToHostTransferredGeoDataWrapper
    geo_data = ToHostTransferredGeoDataWrapper(queue, geo_data_dev)

    # }}}

    # {{{ Construct cost models

    cl_cost_model = QBXCostModel()
    python_cost_model = _PythonQBXCostModel()

    tree = geo_data.tree()
    xlat_cost = make_pde_aware_translation_cost_model(
        tree.targets.shape[0], tree.nlevels
    )

    constant_one_params = QBXCostModel.get_unit_calibration_params()
    constant_one_params["p_qbx"] = 5
    for ilevel in range(tree.nlevels):
        constant_one_params["p_fmm_lev%d" % ilevel] = 10

    cl_cost_factors = cl_cost_model.qbx_cost_factors_for_kernels_from_model(
        queue, tree.nlevels, xlat_cost, constant_one_params
    )

    python_cost_factors = python_cost_model.qbx_cost_factors_for_kernels_from_model(
        None, tree.nlevels, xlat_cost, constant_one_params
    )

    # }}}

    # {{{ Test process_form_qbxl

    cl_ndirect_sources_per_target_box = (
        cl_cost_model.get_ndirect_sources_per_target_box(
            queue, geo_data_dev.traversal()
        )
    )

    queue.finish()
    start_time = time.time()

    cl_p2qbxl = cl_cost_model.process_form_qbxl(
        queue, geo_data_dev, cl_cost_factors["p2qbxl_cost"],
        cl_ndirect_sources_per_target_box
    )

    queue.finish()
    logger.info("OpenCL time for process_form_qbxl: {}".format(
        str(time.time() - start_time)
    ))

    python_ndirect_sources_per_target_box = (
        python_cost_model.get_ndirect_sources_per_target_box(
            queue, geo_data.traversal()
        )
    )

    start_time = time.time()

    python_p2qbxl = python_cost_model.process_form_qbxl(
        queue, geo_data, python_cost_factors["p2qbxl_cost"],
        python_ndirect_sources_per_target_box
    )

    logger.info("Python time for process_form_qbxl: {}".format(
        str(time.time() - start_time)
    ))

    assert np.array_equal(cl_p2qbxl.get(), python_p2qbxl)

    # }}}

    # {{{ Test process_m2qbxl

    queue.finish()
    start_time = time.time()

    cl_m2qbxl = cl_cost_model.process_m2qbxl(
        queue, geo_data_dev, cl_cost_factors["m2qbxl_cost"]
    )

    queue.finish()
    logger.info("OpenCL time for process_m2qbxl: {}".format(
        str(time.time() - start_time)
    ))

    start_time = time.time()

    python_m2qbxl = python_cost_model.process_m2qbxl(
        queue, geo_data, python_cost_factors["m2qbxl_cost"]
    )

    logger.info("Python time for process_m2qbxl: {}".format(
        str(time.time() - start_time)
    ))

    assert np.array_equal(cl_m2qbxl.get(), python_m2qbxl)

    # }}}

    # {{{ Test process_l2qbxl

    queue.finish()
    start_time = time.time()

    cl_l2qbxl = cl_cost_model.process_l2qbxl(
        queue, geo_data_dev, cl_cost_factors["l2qbxl_cost"]
    )

    queue.finish()
    logger.info("OpenCL time for process_l2qbxl: {}".format(
        str(time.time() - start_time)
    ))

    start_time = time.time()

    python_l2qbxl = python_cost_model.process_l2qbxl(
        queue, geo_data, python_cost_factors["l2qbxl_cost"]
    )

    logger.info("Python time for process_l2qbxl: {}".format(
        str(time.time() - start_time)
    ))

    assert np.array_equal(cl_l2qbxl.get(), python_l2qbxl)

    # }}}

    # {{{ Test process_eval_qbxl

    queue.finish()
    start_time = time.time()

    cl_eval_qbxl = cl_cost_model.process_eval_qbxl(
        queue, geo_data_dev, cl_cost_factors["qbxl2p_cost"]
    )

    queue.finish()
    logger.info("OpenCL time for process_eval_qbxl: {}".format(
        str(time.time() - start_time)
    ))

    start_time = time.time()

    python_eval_qbxl = python_cost_model.process_eval_qbxl(
        queue, geo_data, python_cost_factors["qbxl2p_cost"]
    )

    logger.info("Python time for process_eval_qbxl: {}".format(
        str(time.time() - start_time)
    ))

    assert np.array_equal(cl_eval_qbxl.get(), python_eval_qbxl)

    # }}}

    # {{{ Test eval_target_specific_qbxl

    queue.finish()
    start_time = time.time()

    cl_eval_target_specific_qbxl = cl_cost_model.process_eval_target_specific_qbxl(
        queue, geo_data_dev, cl_cost_factors["p2p_tsqbx_cost"],
        cl_ndirect_sources_per_target_box
    )

    queue.finish()
    logger.info("OpenCL time for eval_target_specific_qbxl: {}".format(
        str(time.time() - start_time)
    ))

    start_time = time.time()

    python_eval_target_specific_qbxl = \
        python_cost_model.process_eval_target_specific_qbxl(
            queue, geo_data, python_cost_factors["p2p_tsqbx_cost"],
            python_ndirect_sources_per_target_box
        )

    logger.info("Python time for eval_target_specific_qbxl: {}".format(
        str(time.time() - start_time)
    ))

    assert np.array_equal(
        cl_eval_target_specific_qbxl.get(), python_eval_target_specific_qbxl
    )
Ejemplo n.º 6
0
    def __init__(self,
                 code,
                 queue,
                 geo_data,
                 dtype,
                 qbx_order,
                 fmm_level_to_order,
                 source_extra_kwargs,
                 kernel_extra_kwargs,
                 _use_target_specific_qbx=None):
        self.code = code
        self.queue = queue

        # FMMLib is CPU-only. This wrapper gets the geometry out of
        # OpenCL-land.

        from pytential.qbx.utils import ToHostTransferredGeoDataWrapper
        geo_data = ToHostTransferredGeoDataWrapper(queue, geo_data)

        self.geo_data = geo_data
        self.qbx_order = qbx_order

        # {{{ digest target_kernels

        ifgrad = False
        outputs = []
        source_deriv_names = []
        k_names = []

        using_tsqbx = (
            _use_target_specific_qbx
            # None means use by default if possible
            or _use_target_specific_qbx is None)

        for out_knl in self.code.target_kernels:
            if not self.is_supported_helmknl_for_tsqbx(out_knl):
                if _use_target_specific_qbx:
                    raise ValueError("not all kernels passed support TSQBX")
                using_tsqbx = False

            if self.is_supported_helmknl(out_knl):
                outputs.append(())
                no_target_deriv_knl = out_knl

            elif (isinstance(out_knl, AxisTargetDerivative)
                  and self.is_supported_helmknl(out_knl.inner_kernel)):
                outputs.append((out_knl.axis, ))
                ifgrad = True
                no_target_deriv_knl = out_knl.inner_kernel

            else:
                raise ValueError("only the 2/3D Laplace and Helmholtz kernel "
                                 "and their derivatives are supported")

            source_deriv_names.append(
                no_target_deriv_knl.dir_vec_name if isinstance(
                    no_target_deriv_knl, DirectionalSourceDerivative
                ) else None)

            base_knl = out_knl.get_base_kernel()
            k_names.append(base_knl.helmholtz_k_name if isinstance(
                base_knl, HelmholtzKernel) else None)

        self.using_tsqbx = using_tsqbx
        self.outputs = outputs

        from pytools import is_single_valued

        if not is_single_valued(source_deriv_names):
            raise ValueError("not all kernels passed are the same in "
                             "whether they represent a source derivative")

        source_deriv_name = source_deriv_names[0]

        if not is_single_valued(k_names):
            raise ValueError("not all kernels passed have the same "
                             "Helmholtz parameter")

        k_name = k_names[0]

        if k_name is None:
            helmholtz_k = 0
        else:
            helmholtz_k = kernel_extra_kwargs[k_name]

        # }}}

        dipole_vec = None
        if source_deriv_name is not None:
            dipole_vec = np.array([
                d_i.get(queue=queue)
                for d_i in source_extra_kwargs[source_deriv_name]
            ],
                                  order="F")

        def inner_fmm_level_to_nterms(tree, level):
            if helmholtz_k == 0:
                return fmm_level_to_order(LaplaceKernel(tree.dimensions),
                                          frozenset(), tree, level)
            else:
                return fmm_level_to_order(HelmholtzKernel(tree.dimensions),
                                          frozenset([("k", helmholtz_k)]),
                                          tree, level)

        super().__init__(geo_data.tree(),
                         helmholtz_k=helmholtz_k,
                         dipole_vec=dipole_vec,
                         dipoles_already_reordered=True,
                         fmm_level_to_nterms=inner_fmm_level_to_nterms,
                         rotation_data=geo_data,
                         ifgrad=ifgrad)