Skip to content
Snippets Groups Projects
quadrature.py 8.25 KiB
Newer Older
Dominic Kempf's avatar
Dominic Kempf committed
from dune.codegen.generation import (class_member,
Dominic Kempf's avatar
Dominic Kempf committed
                                     domain,
                                     get_global_context_value,
                                     globalarg,
                                     iname,
                                     include_file,
                                     instruction,
Dominic Kempf's avatar
Dominic Kempf committed
                                     preamble,
                                     quadrature_mixin,
Dominic Kempf's avatar
Dominic Kempf committed
                                     temporary_variable,
                                     valuearg,
                                     )
from dune.codegen.loopy.target import type_floatingpoint
from dune.codegen.pdelab.localoperator import name_ansatz_gfs_constructor_param
Dominic Kempf's avatar
Dominic Kempf committed
from dune.codegen.options import get_form_option
from pymbolic.primitives import Variable, Subscript
import pymbolic.primitives as prim


@quadrature_mixin("base")
class QuadratureMixinBase(object):
    def quad_unhandled(self, o):
        raise NotImplementedError("Quadrature Mixins should handle {}".format(type(o)))

    quadrature_weight = quad_unhandled

    def quadrature_inames(self):
        raise NotImplementedError("Quadrature mixins should provide the quadrature inames!")

    def quadrature_position(self, index=None):
        raise NotImplementedError("Quadrature mixins should provide the quadrature position")


@quadrature_mixin("generic")
class GenericQuadratureMixin(QuadratureMixinBase):
    def quadrature_weight(self, o):
        # Create a name that has all the necessary quantities mangled in
        from dune.codegen.pdelab.geometry import local_dimension
        dim = local_dimension()
        order = quadrature_order()
        name = "qw_dim{}_order{}".format(dim, order)

        shape = name_quadrature_bound()
        globalarg(name, shape=(shape,))
        self.define_quadrature_weights(name)

        return prim.Subscript(prim.Variable(name),
                              tuple(prim.Variable(i) for i in self.quadrature_inames()))

    @class_member(classtag="operator")
    def define_quadrature_weights(self, name):
        from dune.codegen.pdelab.geometry import local_dimension
        dim = local_dimension()
        self.eval_quadrature_weights(name)
        return "mutable std::vector<typename Dune::QuadraturePoint<{}, {}>::Field> {};".format(rf, dim, name)

    @preamble(kernel="operator")
    def eval_quadrature_weights(self, name):
        gfs = name_ansatz_gfs_constructor_param()
        quad_order = quadrature_order()
        include_file("dune/codegen/localbasiscache.hh", filetag='operatorfile')
        entity = "{}.gridView().template begin<0>()".format(gfs)
        if self.measure != "cell":
            entity = "{}.gridView().ibegin(*({}))".format(gfs, entity)
        return "fillQuadratureWeightsCache({}->geometry(), {}, {});".format(entity, quad_order, name)

    def quadrature_inames(self):
        return (quadrature_iname(),)

    def quadrature_position(self, index=None):
        from dune.codegen.pdelab.geometry import local_dimension
        dim = local_dimension()
        order = quadrature_order()
        name = "qp_dim{}_order{}".format(dim, order)

        shape = (name_quadrature_bound(), dim)
        globalarg(name, shape=shape, managed=False)
        self.define_quadrature_points(name)

        qp = prim.Subscript(prim.Variable(name), tuple(prim.Variable(i) for i in self.quadrature_inames()))

        if index is not None:
            qp = prim.Subscript(qp, (index,))

        return qp

    @class_member(classtag="operator")
    def define_quadrature_points(self, name):
        from dune.codegen.pdelab.geometry import local_dimension
        dim = local_dimension()
        self.eval_quadrature_points(name)
        return "mutable std::vector<typename Dune::QuadraturePoint<{}, {}>::Vector> {};".format(rf, dim, name)

    @preamble(kernel="operator")
    def eval_quadrature_points(self, name):
        gfs = name_ansatz_gfs_constructor_param()
        quad_order = quadrature_order()
        include_file("dune/codegen/localbasiscache.hh", filetag='operatorfile')
        entity = "{}.gridView().template begin<0>()".format(gfs)
        if self.measure != "cell":
            entity = "{}.gridView().ibegin(*({}))".format(gfs, entity)
        return "fillQuadraturePointsCache({}->geometry(), {}, {});".format(entity, quad_order, name)
Dominic Kempf's avatar
Dominic Kempf committed

@preamble
def define_quadrature_rule(name):
    include_file('dune/pdelab/common/quadraturerules.hh', filetag='operatorfile')
Dominic Kempf's avatar
Dominic Kempf committed
    from dune.codegen.pdelab.geometry import name_geometry
    geo = name_geometry()
    order = name_quadrature_order()
    return "const auto {} = quadratureRule({}, {});".format(name, geo, order)


def name_quadrature_rule():
    name = "quadrature_rule"
    define_quadrature_rule(name)
    return name


@preamble
def define_quadrature_bound(name):
    quad_rule = name_quadrature_rule()
    return "auto {} = {}.size();".format(name, quad_rule)


def name_quadrature_bound():
    name = "quadrature_size"
    define_quadrature_bound(name)

    # Quadrature bound is a valuearg for loopy
    valuearg(name, dtype=numpy.int32)

    domain("q", name_quadrature_bound())
def quadrature_preamble(visitor, code, **kw):
    kw['tags'] = kw.get('tags', frozenset({})).union(frozenset({"quad"}))
    return instruction(inames=visitor.quadrature_inames(), code=code, **kw)
Dominic Kempf's avatar
Dominic Kempf committed

def name_quadrature_point():
    # Note: Used for qp_in_inside/qp_in_outside
Dominic Kempf's avatar
Dominic Kempf committed

def _estimate_quadrature_order():
    """Estimate quadrature order using polynomial degree estimation from UFL"""
    # According to UFL documentation estimate_total_polynomial_degree
    # should only be called on preprocessed forms.
    data = get_global_context_value("data")
    form = data.object_by_name[get_form_option("form")]
Dominic Kempf's avatar
Dominic Kempf committed
    from dune.codegen.ufl.preprocess import preprocess_form
    form = preprocess_form(form).preprocessed_form

    # Estimate polynomial degree of integrals of current type (eg 'Cell')
    integral_type = get_global_context_value("integral_type")
    integrals = form.integrals_by_type(integral_type)

    # Degree could be a tuple (for TensorProductElements)
    degree = integrals[0].metadata()['estimated_polynomial_degree']
    if isinstance(degree, int):
        degree = (degree,)
    polynomial_degree = [0, ] * len(degree)

    for i in integrals:
        degree = i.metadata()['estimated_polynomial_degree']
        if isinstance(degree, int):
            degree = [degree, ]
        assert(len(polynomial_degree) == len(degree))
        for i in range(len(polynomial_degree)):
            polynomial_degree[i] = max(polynomial_degree[i], degree[i])

    # Return either a tuple or an int
    polynomial_degree = tuple(polynomial_degree)
    if len(polynomial_degree) == 1:
        polynomial_degree = polynomial_degree[0]

    return polynomial_degree


def quadrature_order():
    """Get quadrature order

    Notes:

    - In PDELab quadrature order m means that integration of
      polynomials of degree m is exact.
    - If you use sum factorization and TensorProductElement it is
      possible to use a different quadrature_order per direction.
    if get_form_option("quadrature_order"):
        quadrature_order = tuple(map(int, str(get_form_option("quadrature_order")).split(',')))
    else:
        quadrature_order = _estimate_quadrature_order()
    # TensorProductElements can have different quadrature order for
    # every direction so quadrature_order may be a tuple. If we do not
    # use TensorProductElements we want to return an int.
    if isinstance(quadrature_order, tuple):
        if len(quadrature_order) == 1:
            quadrature_order = quadrature_order[0]
    if isinstance(quadrature_order, tuple):
        if not get_form_option('sumfact'):
            raise NotImplementedError("Different quadrature order per direction is only implemented for kernels using sum factorization.")
Dominic Kempf's avatar
Dominic Kempf committed
        from dune.codegen.pdelab.geometry import world_dimension
        assert(len(quadrature_order) == world_dimension())

    return quadrature_order


def name_quadrature_order():
    # Quadrature order from UFL estimation
    quad_order = quadrature_order()
    return str(quad_order)