diff --git a/python/dune/perftool/pdelab/__init__.py b/python/dune/perftool/pdelab/__init__.py index 76aaff919dd3d63045f811ebe9896a5910b529d5..2ac5432e61419d95d75e624952cac09cc107bdec 100644 --- a/python/dune/perftool/pdelab/__init__.py +++ b/python/dune/perftool/pdelab/__init__.py @@ -22,7 +22,8 @@ from dune.perftool.pdelab.index import (name_index, from dune.perftool.pdelab.parameter import (cell_parameter_function, intersection_parameter_function, ) -from dune.perftool.pdelab.quadrature import (name_quadrature_weight, +from dune.perftool.pdelab.quadrature import (pymbolic_quadrature_weight, + quadrature_inames, ) from dune.perftool.pdelab.spaces import (lfs_iname, ) @@ -102,5 +103,9 @@ class PDELabInterface(object): # Quadrature related generator functions # - def name_quadrature_weight(self): - return name_quadrature_weight() + def pymbolic_quadrature_weight(self): + return pymbolic_quadrature_weight() + + # TODO Should this be part of interface or not? + def quadrature_inames(self): + return quadrature_inames() diff --git a/python/dune/perftool/pdelab/argument.py b/python/dune/perftool/pdelab/argument.py index afcb0e956c1597d526251dcf12efdc86def82d8f..5b72c9b95e54e5796b86c324d6b4c257a15afb06 100644 --- a/python/dune/perftool/pdelab/argument.py +++ b/python/dune/perftool/pdelab/argument.py @@ -169,11 +169,22 @@ def type_residual(): return "R" -def name_accumulation_variable(restrictions=(Restriction.NONE,)): +def name_accumulation_variable(restrictions=None): ft = get_global_context_value("form_type") + measure = get_global_context_value("integral_type") if ft == 'residual' or ft == 'jacobian_apply': + if restrictions is None: + if measure == "cell": + restrictions = (Restriction.NONE,) + else: + restrictions = (Restriction.OUTSIDE,) return name_residual(*restrictions) if ft == 'jacobian': + if restrictions is None: + if measure == "cell": + restrictions = (Restriction.NONE, Restriction.NONE) + else: + restrictions = (Restriction.OUTSIDE, Restriction.OUTSIDE) return name_jacobian(*restrictions) assert False diff --git a/python/dune/perftool/pdelab/basis.py b/python/dune/perftool/pdelab/basis.py index ad587091096fff8a51debf2002332da2412890bf..aacbcac00980c871c9af99fb73cf537065eb5527 100644 --- a/python/dune/perftool/pdelab/basis.py +++ b/python/dune/perftool/pdelab/basis.py @@ -1,9 +1,9 @@ """ Generators for basis evaluations """ -from dune.perftool.generation import (backend, - cached, +from dune.perftool.generation import (cached, class_member, generator_factory, + get_backend, include_file, instruction, preamble, @@ -66,9 +66,8 @@ def evaluate_basis(leaf_element, name, restriction): temporary_variable(name, shape=(name_lfs_bound(lfs),), decl_method=None) declare_cache_temporary(leaf_element, restriction, name, which='Function') cache = name_localbasis_cache(leaf_element) - qp = name_quadrature_position_in_cell(restriction) - instruction(inames=(quadrature_iname(), - ), + qp = get_backend("qp_in_cell")(restriction) + instruction(inames=get_backend("quad_inames")(), code='{} = {}.evaluateFunction({}, {}.finiteElement().localBasis());'.format(name, cache, qp, @@ -95,8 +94,7 @@ def evaluate_reference_gradient(leaf_element, name, restriction): declare_cache_temporary(leaf_element, restriction, name, which='Jacobian') cache = name_localbasis_cache(leaf_element) qp = name_quadrature_position_in_cell(restriction) - instruction(inames=(quadrature_iname(), - ), + instruction(inames=get_backend("quad_inames")(), code='{} = {}.evaluateJacobian({}, {}.finiteElement().localBasis());'.format(name, cache, qp, @@ -124,7 +122,6 @@ def shape_as_pymbolic(shape): return tuple(_shape_as_pymbolic(s) for s in shape) -@backend(interface="eval_coefficient") @cached def evaluate_coefficient(element, name, container, restriction, component): from ufl.functionview import select_subelement @@ -156,7 +153,7 @@ def evaluate_coefficient(element, name, container, restriction, component): reduction_expr = Product((coeff, Subscript(Variable(basis), Variable(index)))) instruction(expression=Reduction("sum", index, reduction_expr, allow_simultaneous=True), assignee=assignee, - forced_iname_deps=frozenset({quadrature_iname()}).union(frozenset(idims)), + forced_iname_deps=frozenset(get_backend("quad_inames")()).union(frozenset(idims)), forced_iname_deps_is_final=True, ) @@ -195,6 +192,6 @@ def evaluate_coefficient_gradient(element, name, container, restriction, compone instruction(expression=Reduction("sum", index, reduction_expr, allow_simultaneous=True), assignee=assignee, - forced_iname_deps=frozenset({quadrature_iname()}).union(frozenset(idims)), + forced_iname_deps=frozenset(get_backend("quad_inames")()).union(frozenset(idims)), forced_iname_deps_is_final=True, ) diff --git a/python/dune/perftool/pdelab/geometry.py b/python/dune/perftool/pdelab/geometry.py index 8dd41c1237c43e76d11a10d4b94365d98fbdd472..1210a6a07622a80b90aa2716d9e27515ea8f1148 100644 --- a/python/dune/perftool/pdelab/geometry.py +++ b/python/dune/perftool/pdelab/geometry.py @@ -2,6 +2,7 @@ from dune.perftool.ufl.modified_terminals import Restriction from dune.perftool.pdelab.restriction import restricted_name from dune.perftool.generation import (cached, domain, + get_backend, get_global_context_value, iname, preamble, @@ -254,7 +255,7 @@ def define_jacobian_inverse_transposed(name, restriction): dim = name_dimension() temporary_variable(name, decl_method=define_jacobian_inverse_transposed_temporary(restriction), shape=(dim, dim)) geo = name_cell_geometry(restriction) - pos = name_quadrature_position_in_cell(restriction) + pos = get_backend("qp_in_cell")(restriction) return quadrature_preamble("{} = {}.jacobianInverseTransposed({});".format(name, geo, pos, @@ -273,7 +274,7 @@ def name_jacobian_inverse_transposed(restriction): def define_jacobian_determinant(name): temporary_variable(name, shape=()) geo = name_geometry() - pos = name_quadrature_position() + pos = get_backend("quad_pos")() code = "{} = {}.integrationElement({});".format(name, geo, pos, diff --git a/python/dune/perftool/pdelab/localoperator.py b/python/dune/perftool/pdelab/localoperator.py index 5f9ac0d9bd952d9e21cbba86a4db53477be97944..33af5b7a500dc9627cc9735e306b7baa93513934 100644 --- a/python/dune/perftool/pdelab/localoperator.py +++ b/python/dune/perftool/pdelab/localoperator.py @@ -403,13 +403,13 @@ def generate_accumulation_instruction(visitor, accterm, measure, subdomain_id): (ansatz_lfs.get_args() + test_lfs.get_args() + (pymbolic_expr,)) ) - from dune.perftool.generation import get_backend, instruction + from dune.perftool.generation import instruction from dune.perftool.options import option_switch - quad_inames = get_backend(interface="quadinames", selector=option_switch("sumfac"))() + quad_inames = visitor.interface.quadrature_inames() instruction(assignees=(), expression=expr, - forced_iname_deps=additional_inames.union(frozenset(visitor.inames).union(quad_inames)), + forced_iname_deps=additional_inames.union(frozenset(visitor.inames).union(frozenset(quad_inames))), forced_iname_deps_is_final=True, predicates=predicates ) @@ -459,8 +459,12 @@ def generate_kernel(integrals): indexmap[j] = indexmap[i] # Get a transformer instance for this kernel - from dune.perftool.pdelab import PDELabInterface - interface = PDELabInterface() + if get_option('sumfact'): + from dune.perftool.sumfact import SumFactInterface + interface = SumFactInterface() + else: + from dune.perftool.pdelab import PDELabInterface + interface = PDELabInterface() from dune.perftool.ufl.visitor import UFL2LoopyVisitor visitor = UFL2LoopyVisitor(interface, measure, indexmap) generate_accumulation_instruction(visitor, term, measure, subdomain_id) diff --git a/python/dune/perftool/pdelab/quadrature.py b/python/dune/perftool/pdelab/quadrature.py index b50c8248512ce363cb35b735c199698102ddf110..030c467cc94c14d22bc31c203f9bd2da81953692 100644 --- a/python/dune/perftool/pdelab/quadrature.py +++ b/python/dune/perftool/pdelab/quadrature.py @@ -1,6 +1,7 @@ from dune.perftool.generation import (backend, cached, domain, + get_backend, get_global_context_value, iname, include_file, @@ -10,6 +11,8 @@ from dune.perftool.generation import (backend, from dune.perftool.options import get_option from dune.perftool.ufl.modified_terminals import Restriction +from pymbolic.primitives import Variable + @iname def quadrature_iname(): @@ -17,13 +20,13 @@ def quadrature_iname(): return "q" -@backend(interface="quadinames") +@backend(interface="quad_inames") def quadrature_inames(): - return frozenset({quadrature_iname()}) + return (quadrature_iname(),) def quadrature_preamble(code, **kw): - return instruction(inames=quadrature_iname(), code=code, **kw) + return instruction(inames=get_backend(interface="quad_inames")(), code=code, **kw) def name_quadrature_point(): @@ -37,6 +40,7 @@ def define_quadrature_position(name): ) +@backend(interface="quad_pos") def name_quadrature_position(): name = "pos" # To determine the shape, I do query global information here for lack of good alternatives @@ -52,6 +56,7 @@ def name_quadrature_position(): return name +@backend(interface="qp_in_cell") def name_quadrature_position_in_cell(restriction): if restriction == Restriction.NONE: return name_quadrature_position() @@ -67,11 +72,11 @@ def define_quadrature_weight(name): ) -def name_quadrature_weight(): +def pymbolic_quadrature_weight(): name = 'weight' temporary_variable(name, shape=()) define_quadrature_weight(name) - return name + return Variable(name) def estimate_quadrature_order(): diff --git a/python/dune/perftool/pdelab/spaces.py b/python/dune/perftool/pdelab/spaces.py index 07403a8641ba8701ccd3a89a8c9c619ef8167df9..0e7b0ce29818b72082a55ba795844d2ebf18747f 100644 --- a/python/dune/perftool/pdelab/spaces.py +++ b/python/dune/perftool/pdelab/spaces.py @@ -212,6 +212,24 @@ def lfs_iname(element, restriction, count=None, context=''): return _lfs_iname(element, restriction, context) +class LFSLocalIndex(FunctionIdentifier): + def __init__(self, lfs): + self.lfs = lfs + + def __getinitargs__(self): + return (self.lfs,) + + @property + def name(self): + return '{}.local_index'.format(self.lfs) + + +@function_mangler +def lfs_localindex_mangler(target, func, dtypes): + if isinstance(func, LFSLocalIndex): + return CallMangleInfo(func.name, (NumpyType(numpy.int32),), (NumpyType(numpy.int32),)) + + def name_testfunctionspace(restriction): return restricted_name("lfsv", restriction) diff --git a/python/dune/perftool/sumfact/__init__.py b/python/dune/perftool/sumfact/__init__.py index 3f081643c4230fa3168db58beef408640e2a5290..e263c742444e51ccbb301eade94ffcd60472756d 100644 --- a/python/dune/perftool/sumfact/__init__.py +++ b/python/dune/perftool/sumfact/__init__.py @@ -1,6 +1,18 @@ -# Trigger some imports that are needed to have all backend implementations visible -# to the selection mechanisms -import dune.perftool.sumfact.amatrix -import dune.perftool.sumfact.sumfact +from dune.perftool.sumfact.quadrature import (quadrature_inames, + quadrature_weight, + ) -from dune.perftool.sumfact.sumfact import start_sumfactorization +from dune.perftool.sumfact.sumfact import pymbolic_trialfunction + +from dune.perftool.pdelab import PDELabInterface + + +class SumFactInterface(PDELabInterface): + def pymbolic_trialfunction(self, element, restriction, component): + return pymbolic_trialfunction(element, restriction, component) + + def quadrature_inames(self): + return quadrature_inames() + + def pymbolic_quadrature_weight(self): + return quadrature_weight() diff --git a/python/dune/perftool/sumfact/amatrix.py b/python/dune/perftool/sumfact/amatrix.py index 968f4f16de04ce7daace2e19f74185ff24380222..1d878add55b3d52c0c539890380e06e3b784a922 100644 --- a/python/dune/perftool/sumfact/amatrix.py +++ b/python/dune/perftool/sumfact/amatrix.py @@ -125,6 +125,7 @@ def define_oned_quadrature_weights(name): def name_oned_quadrature_weights(): name = "qw" + globalarg(name, shape=(quadrature_points_per_direction(),), dtype=NumpyType(numpy.float64)) define_oned_quadrature_weights(name) return name @@ -138,6 +139,7 @@ def define_oned_quadrature_points(name): def name_oned_quadrature_points(): name = "qp" + globalarg(name, shape=(quadrature_points_per_direction(),), dtype=NumpyType(numpy.float64)) define_oned_quadrature_points(name) return name diff --git a/python/dune/perftool/sumfact/quadrature.py b/python/dune/perftool/sumfact/quadrature.py new file mode 100644 index 0000000000000000000000000000000000000000..ea7104a4c8316f7aff23fd3f4a7f9f6dbdc040e6 --- /dev/null +++ b/python/dune/perftool/sumfact/quadrature.py @@ -0,0 +1,114 @@ +from dune.perftool.generation import (backend, + domain, + function_mangler, + get_global_context_value, + iname, + instruction, + temporary_variable, + ) + +from dune.perftool.sumfact.amatrix import (name_number_of_basis_functions_per_direction, + name_oned_quadrature_points, + name_oned_quadrature_weights, + ) +from dune.perftool.pdelab.argument import name_accumulation_variable +from dune.perftool.pdelab.geometry import dimension_iname + +from loopy import CallMangleInfo +from loopy.symbolic import FunctionIdentifier +from loopy.types import NumpyType + +from pymbolic.primitives import (Call, + Product, + Subscript, + Variable, + ) + +import numpy + + +class BaseWeight(FunctionIdentifier): + def __init__(self, accumobj): + self.accumobj = accumobj + + def __getinitargs__(self): + return (self.accumobj,) + + @property + def name(self): + return '{}.weight'.format(self.accumobj) + + +@function_mangler +def base_weight_function_mangler(target, func, dtypes): + if isinstance(func, BaseWeight): + return CallMangleInfo(func.name, (NumpyType(numpy.float64),), ()) + + +@iname +def sumfact_quad_iname(d, context): + name = "quad_{}_{}".format(context, d) + domain(name, name_number_of_basis_functions_per_direction()) + return name + + +@backend(interface="quad_inames", name="sumfact") +def quadrature_inames(context=''): + formdata = get_global_context_value('formdata') + dim = formdata.geometric_dimension + return tuple(sumfact_quad_iname(d, context) for d in range(dim)) + + +def define_recursive_quadrature_weight(name, dir): + iname = quadrature_inames()[dir] + temporary_variable(name, shape=(), shape_impl=()) + instruction(expression=Product((recursive_quadrature_weight(dir + 1), + Subscript(Variable(name_oned_quadrature_weights()), + (Variable(iname),) + )) + ), + assignee=Variable(name), + forced_iname_deps=frozenset(quadrature_inames()[dir:]), + forced_iname_deps_is_final=True, + ) + + +def recursive_quadrature_weight(dir=0): + formdata = get_global_context_value('formdata') + dim = formdata.geometric_dimension + if dir == dim: + return Call(BaseWeight(name_accumulation_variable()), ()) + else: + name = 'weight_{}'.format(dir) + define_recursive_quadrature_weight(name, dir) + return Variable(name) + + +def quadrature_weight(): + return recursive_quadrature_weight() + + +def define_quadrature_position(name): + formdata = get_global_context_value('formdata') + dim = formdata.geometric_dimension + for i in range(dim): + instruction(expression=Subscript(Variable(name_oned_quadrature_points()), (Variable(quadrature_inames()[i]),)), + assignee=Subscript(Variable(name), (i,)), + forced_iname_deps=frozenset(quadrature_inames()), + forced_iname_deps_is_final=True, + ) + + +@backend(interface="quad_pos", name="sumfact") +def name_quadrature_position(): + formdata = get_global_context_value('formdata') + dim = formdata.geometric_dimension + name = 'pos' + temporary_variable(name, shape=(dim,), shape_impl=("fv",)) + define_quadrature_position(name) + return name + + +@backend(interface="qp_in_cell", name="sumfact") +def name_quadrature_position_in_cell(restriction): + return name_quadrature_position() diff --git a/python/dune/perftool/sumfact/sumfact.py b/python/dune/perftool/sumfact/sumfact.py index 5a3e364d2705281f8184ceb1ab4b013956bba50a..37be6d7d9b7e297181914f54af42a7111608178a 100644 --- a/python/dune/perftool/sumfact/sumfact.py +++ b/python/dune/perftool/sumfact/sumfact.py @@ -1,4 +1,6 @@ -from dune.perftool.pdelab.argument import pymbolic_coefficient +from dune.perftool.pdelab.argument import (name_coefficientcontainer, + pymbolic_coefficient, + ) from dune.perftool.generation import (backend, domain, get_counter, @@ -23,7 +25,7 @@ from pymbolic.primitives import (Call, Subscript, Variable, ) - +from dune.perftool.sumfact.quadrature import quadrature_inames from loopy import Reduction from pytools import product @@ -42,7 +44,7 @@ def sumfact_iname(bound, _type): return name -def setup_theta(element, container, restriction, component, a_matrices): +def setup_theta(element, restriction, component, a_matrices): number_basis = product(mat.cols for mat in a_matrices) shape = (number_basis,) inp = get_buffer_temporary("buffer", @@ -52,6 +54,7 @@ def setup_theta(element, container, restriction, component, a_matrices): # Write initial coefficients into buffer basisiname = sumfact_iname(number_basis, "basis") lfs = name_lfs(element, restriction, component) + container = name_coefficientcontainer(restriction) coeff = pymbolic_coefficient(container, lfs, basisiname) assignee = Subscript(Variable(inp), (Variable(basisiname),)) return instruction(assignee=assignee, @@ -60,9 +63,7 @@ def setup_theta(element, container, restriction, component, a_matrices): ) -# TODO this code is WIP and mainly used for experiments. -@backend(interface="eval_coefficient", name="sumfact") -def start_sumfactorization(element, name, container, restriction, component): +def pymbolic_trialfunction(element, restriction, component): theta = name_theta() rows = quadrature_points_per_direction() cols = basis_functions_per_direction() @@ -75,16 +76,17 @@ def start_sumfactorization(element, name, container, restriction, component): num=2 ) - insn_dep = setup_theta(element, container, restriction, component, a_matrices) + insn_dep = setup_theta(element, restriction, component, a_matrices) + var = sum_factorization_kernel(a_matrices, "buffer", 0, frozenset({insn_dep})) - sum_factorization_kernel(a_matrices, "buffer", 0, frozenset({insn_dep})) + return Subscript(Variable(var), tuple(Variable(i) for i in quadrature_inames())) - # Do stage 3 (for f=u => mass matrix) - theta_transposed = name_theta_transposed() - a_matrix_transposed = AMatrix(theta_transposed, cols, rows) - a_matrices_transposed = (a_matrix_transposed, a_matrix_transposed) - return sum_factorization_kernel(a_matrices_transposed, "buffer", 2) +# # Do stage 3 (for f=u => mass matrix) +# theta_transposed = name_theta_transposed() +# a_matrix_transposed = AMatrix(theta_transposed, cols, rows) +# a_matrices_transposed = (a_matrix_transposed, a_matrix_transposed) +# var = sum_factorization_kernel(a_matrices_transposed, "buffer", 2) def sum_factorization_kernel(a_matrices, buffer, stage, insn_dep=frozenset({})): diff --git a/python/dune/perftool/ufl/visitor.py b/python/dune/perftool/ufl/visitor.py index d87c5dcf57f395c6f6ef47359b44825557c776d8..7a7ff15a1eee44714b3d77ac15bad4f04d3a977a 100644 --- a/python/dune/perftool/ufl/visitor.py +++ b/python/dune/perftool/ufl/visitor.py @@ -256,7 +256,7 @@ class UFL2LoopyVisitor(ModifiedTerminalTracker): return Variable(self.interface.name_unit_inner_normal()) def quadrature_weight(self, o): - return Variable(self.interface.name_quadrature_weight()) + return self.interface.pymbolic_quadrature_weight() def jacobian_determinant(self, o): return Variable(self.interface.name_jacobian_determinant())