Skip to content
scalability_urchin.py 5.06 KiB
Newer Older
import pyopencl as cl
from sympy.core.cache import clear_cache
import numpy as np
Hao Gao's avatar
Hao Gao committed
from pytential import bind, sym
from sumpy.kernel import LaplaceKernel
from pytential.qbx import QBXLayerPotentialSource
from pytential.qbx.distributed import DistributedQBXLayerPotentialSource
from mpi4py import MPI
import logging
import os
import warnings
Hao Gao's avatar
Hao Gao committed
import functools
Hao Gao's avatar
Hao Gao committed
# Parameters
k = 0
qbx_order = 3
fmm_order = 10
_expansion_stick_out_factor = 0.5

# Configure logging
logging.basicConfig(level=os.environ.get("LOGLEVEL", "WARNING"))
logging.getLogger("pytential.qbx.distributed").setLevel(logging.INFO)

warnings.filterwarnings("ignore", category=UserWarning)

# Disable sympy cache
clear_cache()

# Setup PyOpenCL
ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)


class GreenExpr(object):
    zero_op_name = "green"

    def get_zero_op(self, kernel, **knl_kwargs):

        u_sym = sym.var("u")
        dn_u_sym = sym.var("dn_u")

        return (
            sym.S(kernel, dn_u_sym, qbx_forced_limit=-1, **knl_kwargs)
            - sym.D(kernel, u_sym, qbx_forced_limit="avg", **knl_kwargs)
            - 0.5*u_sym)

    order_drop = 0


def get_urchin_mesh(m, n, order, est_rel_interp_tolerance):
Hao Gao's avatar
Hao Gao committed
    from meshmode.mesh.generation import refine_mesh_and_get_urchin_warper
    refiner, warp_mesh = refine_mesh_and_get_urchin_warper(
        order, m, n, est_rel_interp_tolerance
    )
Hao Gao's avatar
Hao Gao committed
    return refiner.get_current_mesh()


expr = GreenExpr()

Hao Gao's avatar
Hao Gao committed

def generate_expr(m, n, target_order, est_rel_interp_tolerance, lp_source_contructor):
    mesh = get_urchin_mesh(m, n, target_order, est_rel_interp_tolerance)
    d = mesh.ambient_dim
Hao Gao's avatar
Hao Gao committed

    lap_k_sym = LaplaceKernel(d)
    k_sym = lap_k_sym
    knl_kwargs = {}

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
        InterpolatoryQuadratureSimplexGroupFactory
Hao Gao's avatar
Hao Gao committed

    pre_density_discr = Discretization(
        ctx, mesh,
Hao Gao's avatar
Hao Gao committed
        InterpolatoryQuadratureSimplexGroupFactory(target_order)
    )

    refiner_extra_kwargs = {}

    qbx, _ = lp_source_contructor(
        pre_density_discr, 4 * target_order,
        qbx_order,
        fmm_order=fmm_order,
        _expansions_in_tree_have_extent=True,
        _expansion_stick_out_factor=_expansion_stick_out_factor
    ).with_refinement(**refiner_extra_kwargs)

    density_discr = qbx.density_discr

    # {{{ compute values of a solution to the PDE

    nodes_host = density_discr.nodes().get(queue)
    normal = bind(density_discr, sym.normal(d))(queue).as_vector(np.object)
    normal_host = [normal[j].get() for j in range(d)]

    center = np.array([3, 1, 2])[:d]
    diff = nodes_host - center[:, np.newaxis]
    dist_squared = np.sum(diff ** 2, axis=0)
    dist = np.sqrt(dist_squared)
    if d == 2:
        u = np.log(dist)
        grad_u = diff / dist_squared
    elif d == 3:
        u = 1 / dist
        grad_u = -diff / dist ** 3
    else:
        assert False

    dn_u = 0
    for i in range(d):
        dn_u = dn_u + normal_host[i] * grad_u[i]

    # }}}

    u_dev = cl.array.to_device(queue, u)
    dn_u_dev = cl.array.to_device(queue, dn_u)
    grad_u_dev = cl.array.to_device(queue, grad_u)

    bound_op = bind(qbx, expr.get_zero_op(k_sym, **knl_kwargs))

    return bound_op, {'u': u_dev, 'dn_u': dn_u_dev, 'grad_u': grad_u_dev, 'k': k}

Hao Gao's avatar
Hao Gao committed

def train():
    from pytential.qbx.perf_model import QBXPerformanceModel
    model = QBXPerformanceModel(ctx, True)

    model.loadjson('model.json')

    training_cases = [
        # (20, 30, 5, 0.01)
        (20, 30, 5, 0.005)
Hao Gao's avatar
Hao Gao committed
    lp_source_contructor = functools.partial(QBXLayerPotentialSource, fmm_backend='fmmlib')

    for m, n, target_order, est_rel_interp_tolerance in training_cases:
        expr, context = generate_expr(m, n, target_order, est_rel_interp_tolerance, lp_source_contructor)
        model.time_qbx_performance(queue, expr, context)

    model.savejson('model.json')

Hao Gao's avatar
Hao Gao committed

def evaluate():
    # MPI information
    comm = MPI.COMM_WORLD
    current_rank = comm.Get_rank()

    if current_rank == 0:
        current_dir = os.path.dirname(os.path.abspath(__file__))
        perf_model_file_path = os.path.join(current_dir, 'model.json')
        lp_source_contructor = functools.partial(
            DistributedQBXLayerPotentialSource,
            comm,
            perf_model_file_path=perf_model_file_path
        )

Hao Gao's avatar
Hao Gao committed
        bound_op, context = generate_expr(3, 0.0001, lp_source_contructor)
        bound_op.eval(queue, context=context)
    else:
Hao Gao's avatar
Hao Gao committed
        for _ in range(2):
            lp_source = DistributedQBXLayerPotentialSource(comm, None, None)
            distribute_geo_data = lp_source.distibuted_geo_data(None, queue, None)
Hao Gao's avatar
Hao Gao committed
            from pytential.qbx.distributed import drive_dfmm
            weights = None
            drive_dfmm(queue, weights, distribute_geo_data, comm=comm)


if __name__ == '__main__':
    import sys
    if len(sys.argv) != 2:
        raise RuntimeError("Please specify train or eval")

    if sys.argv[1] == 'train':
        train()
    elif sys.argv[1] == 'eval':
Hao Gao's avatar
Hao Gao committed
        evaluate()
    else:
Hao Gao's avatar
Hao Gao committed
        raise RuntimeError("Unrecognized command line argument. Please specify train or eval.")