Skip to content
scalability.py 4.89 KiB
Newer Older
import pyopencl as cl
from sympy.core.cache import clear_cache
import numpy as np
from meshmode.discretization import Discretization
from pytential import bind, sym, norm
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

# 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_sphere_mesh(refinement_increment, target_order):
    from meshmode.mesh.generation import generate_icosphere
    mesh = generate_icosphere(1, target_order)
    from meshmode.mesh.refinement import Refiner

    refiner = Refiner(mesh)
    for i in range(refinement_increment):
        flags = np.ones(mesh.nelements, dtype=bool)
        refiner.refine(flags)
        mesh = refiner.get_current_mesh()

    return mesh

# Parameters
k = 0
qbx_order = 3
fmm_order = 10
_expansion_stick_out_factor = 0.5

expr = GreenExpr()

def generate_expr(refinement_increment, target_order, lp_source_contructor):
    mesh = get_sphere_mesh(refinement_increment, target_order)
    d = mesh.ambient_dim
    
    lap_k_sym = LaplaceKernel(d)
    k_sym = lap_k_sym
    knl_kwargs = {}

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
        InterpolatoryQuadratureSimplexGroupFactory
    
    pre_density_discr = Discretization(
        ctx, mesh,
        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}

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

    model.loadjson('model.json')

    training_cases = [
        (0, 6),
        (0, 6),
        (0, 8),
        (1, 8),
        (1, 10),
        (1, 10)
    ]

    for refinement_increment, target_order in training_cases:
        expr, context = generate_expr(refinement_increment, target_order, QBXLayerPotentialSource)
        model.time_qbx_performance(queue, expr, context)

    model.savejson('model.json')

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

    if current_rank == 0:
        import functools
        lp_source_contructor = functools.partial(DistributedQBXLayerPotentialSource, comm)

        bound_op, context = generate_expr(3, 10, lp_source_contructor)
        bound_op.eval(queue, context=context)
    else:
        lp_source = DistributedQBXLayerPotentialSource(comm, None, None)
        distribute_geo_data = lp_source.distibuted_geo_data(None, queue, None)

        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':
        eval()
    else:
        raise RuntimeError("Unrecognized command line argument. Please specify train or eval.")