From 067f6783e0f1928227d4b69e34c429f00409778b Mon Sep 17 00:00:00 2001 From: Dominic Kempf <dominic.kempf@iwr.uni-heidelberg.de> Date: Thu, 28 Apr 2016 13:30:31 +0200 Subject: [PATCH] Big chunk of work piping restrictions through the infrastructure --- python/dune/perftool/loopy/transformer.py | 78 +++--- python/dune/perftool/pdelab/__init__.py | 10 + python/dune/perftool/pdelab/argument.py | 64 +++-- python/dune/perftool/pdelab/basis.py | 119 +++++----- python/dune/perftool/pdelab/driver.py | 2 +- python/dune/perftool/pdelab/geometry.py | 101 ++++---- python/dune/perftool/pdelab/localoperator.py | 83 +++---- python/dune/perftool/pdelab/parameter.py | 10 +- python/dune/perftool/pdelab/quadrature.py | 4 +- python/dune/perftool/pdelab/signatures.py | 238 +++++++++++++++++++ python/dune/perftool/pymbolic/uflmapper.py | 3 + test/laplace/CMakeLists.txt | 7 + test/laplace/laplace_dg_numdiff.mini | 2 +- test/laplace/laplace_dg_symdiff.mini | 6 + 14 files changed, 499 insertions(+), 228 deletions(-) create mode 100644 python/dune/perftool/pdelab/signatures.py create mode 100644 test/laplace/laplace_dg_symdiff.mini diff --git a/python/dune/perftool/loopy/transformer.py b/python/dune/perftool/loopy/transformer.py index 49a3f5d1..5ec24a16 100644 --- a/python/dune/perftool/loopy/transformer.py +++ b/python/dune/perftool/loopy/transformer.py @@ -55,7 +55,7 @@ class UFL2LoopyVisitor(ModifiedTerminalTracker, UFL2PymbolicMapper, GeometryMapp if o.on_intersection: intersection_parameter_function(name, o) else: - cell_parameter_function(name, o) + cell_parameter_function(name, o, self.restriction) # And return a symbol from pymbolic.primitives import Variable @@ -101,21 +101,28 @@ def transform_accumulation_term(term, measure, subdomain_id): rmap = {} for ma in test_ma: - with global_context(restriction=ma.restriction): - # Set up the local function space structure - traverse_lfs_tree(ma) + # If this is a boundary integral, all terms are implicitly restricted to the inside cell + if measure == 'exterior_facet': + ma.restriction = Restriction.NEGATIVE + + # Set up the local function space structure + traverse_lfs_tree(ma) + + # Get the expression for the modified argument representing the test function + from dune.perftool.pdelab.argument import pymbolic_testfunction + rmap[ma.expr] = pymbolic_testfunction(ma) - # Get the expression for the modified argument representing the test function - from dune.perftool.pdelab.argument import pymbolic_testfunction - rmap[ma.expr] = pymbolic_testfunction(ma) for ma in trial_ma: - with global_context(restriction=ma.restriction): - # Set up the local function space structure - traverse_lfs_tree(ma) + # If this is a boundary integral, all terms are implicitly restricted to the inside cell + if measure == 'exterior_facet': + ma.restriction = Restriction.NEGATIVE + + # Set up the local function space structure + traverse_lfs_tree(ma) - # Get the expression for the modified argument representing the trial function - from dune.perftool.pdelab.argument import pymbolic_trialfunction - rmap[ma.expr] = pymbolic_trialfunction(ma) + # Get the expression for the modified argument representing the trial function + from dune.perftool.pdelab.argument import pymbolic_trialfunction + rmap[ma.expr] = pymbolic_trialfunction(ma) # Get the transformer! ufl2l_mf = UFL2LoopyVisitor() @@ -135,7 +142,6 @@ def transform_accumulation_term(term, measure, subdomain_id): # Define a temporary variable for this expression expr_tv_name = "expr_" + str(get_count()).zfill(4) - expr_tv = temporary_variable(expr_tv_name) from pymbolic.primitives import Variable # This is a bit hacky now. To correctly determine the iname dependencies of @@ -151,40 +157,54 @@ def transform_accumulation_term(term, measure, subdomain_id): forced_iname_deps_is_final=True, ) + # Actually, if we have a cache hit, we need to change our temporary + from dune.perftool.generation import retrieve_cache_items + expr_tv_name = filter(lambda i: i.id == insn_id, retrieve_cache_items("instruction"))[0].assignee_name + + # Now register the temporary variable with loopy + expr_tv = temporary_variable(expr_tv_name) + # The data that is used to collect the arguments for the accumulate function accumargs = [] residual_shape = {} + arg_restr = [None] * len(test_ma) + + # Determine whether the inames in the jacobian case clash. This is the case, when + # we have a galerkin method. + galerkin = False + if len(test_ma) == 2: + galerkin = (test_ma[0].argexpr.element() == test_ma[1].argexpr.element()) # Generate the code for the modified arguments: for arg in test_ma: from dune.perftool.pdelab.argument import pymbolic_argument from dune.perftool.pdelab.basis import name_lfs accumargs.append(name_lfs(arg.argexpr.element())) - accumargs.append(lfs_iname(arg.argexpr.element(), argcount=arg.argexpr.count())) + + if galerkin and arg.argexpr.count() == 1: + iname = lfs_iname(arg.argexpr.element(), context="arg") + else: + iname = lfs_iname(arg.argexpr.element()) + + accumargs.append(iname) + + # Add this iname to the set of used inames for dependencies later on + acc_inames = acc_inames.union(frozenset({iname})) # Determine the shape residual_shape[arg.argexpr.number()] = name_lfs_bound(name_lfs(arg.argexpr.element())) - from dune.perftool.pdelab.argument import name_jacobian, name_residual - if len(test_ma) == 1: - accumvar = name_residual() - else: - accumvar = name_jacobian() + # Determine the restriction for later + arg_restr[arg.argexpr.count()] = arg.restriction + + from dune.perftool.pdelab.argument import name_accumulation_variable + accumvar = name_accumulation_variable(arg_restr) # The residual/the jacobian should be represented through a loopy global argument # TODO this seems still a bit hacky, esp. w.r.t. systems shape = tuple(v for k, v in sorted(residual_shape.items(), key=lambda (k, v): k)) globalarg(accumvar, shape=shape) - # In the jacobian case we might need to enforce the second loop! - if len(test_ma) == 2: - def _get_element(test_ma): - for ma in test_ma: - if ma.argexpr.count() == 1: - return ma.argexpr.element() - - acc_inames = acc_inames.union(frozenset({lfs_iname(_get_element(test_ma), argcount=1)})) - from dune.perftool.pdelab.quadrature import name_factor factor = name_factor() diff --git a/python/dune/perftool/pdelab/__init__.py b/python/dune/perftool/pdelab/__init__.py index 801c50f8..0f576010 100644 --- a/python/dune/perftool/pdelab/__init__.py +++ b/python/dune/perftool/pdelab/__init__.py @@ -17,3 +17,13 @@ def name_index(index): assert len(index) == 1 # return str(index._indices[0]) return "i_{}".format(index._indices[0].count()) + + +def restricted_name(name, restriction): + from dune.perftool import Restriction + if restriction == Restriction.NONE: + return name + if restriction == Restriction.POSITIVE: + return name + '_n' + if restriction == Restriction.NEGATIVE: + return name + '_s' diff --git a/python/dune/perftool/pdelab/argument.py b/python/dune/perftool/pdelab/argument.py index 3ea5c1d8..f70f3fc9 100644 --- a/python/dune/perftool/pdelab/argument.py +++ b/python/dune/perftool/pdelab/argument.py @@ -2,7 +2,9 @@ from dune.perftool.generation import domain, iname, pymbolic_expr, symbol, globalarg from dune.perftool.ufl.modified_terminals import ModifiedArgumentDescriptor -from dune.perftool.pdelab import name_index +from dune.perftool.pdelab import (name_index, + restricted_name, + ) from dune.perftool.pdelab.basis import (evaluate_trialfunction, evaluate_trialfunction_gradient, lfs_iname, @@ -10,7 +12,7 @@ from dune.perftool.pdelab.basis import (evaluate_trialfunction, name_basis_gradient, name_lfs_bound, ) - +from dune.perftool import Restriction from pymbolic.primitives import Subscript, Variable @@ -18,14 +20,14 @@ from pymbolic.primitives import Subscript, Variable def name_testfunction_gradient(ma): assert ma.grad - return name_basis_gradient(ma.argexpr.element()) + return name_basis_gradient(ma.argexpr.element(), ma.restriction) @symbol def name_testfunction(ma): assert not ma.grad - return name_basis(ma.argexpr.element()) + return name_basis(ma.argexpr.element(), ma.restriction) @pymbolic_expr @@ -43,17 +45,18 @@ def pymbolic_testfunction(ma): def name_trialfunction_gradient(ma): assert ma.grad - evaluate_trialfunction_gradient(ma.argexpr.element(), "gradu") - return "gradu" + name = restricted_name("gradu", ma.restriction) + evaluate_trialfunction_gradient(ma.argexpr.element(), name, ma.restriction) + return name @symbol def name_trialfunction(ma): assert not ma.grad - # TODO trigger the evaluation of the trial function - evaluate_trialfunction(ma.argexpr.element(), "u") - return "u" + name = restricted_name("u", ma.restriction) + evaluate_trialfunction(ma.argexpr.element(), name, ma.restriction) + return name @pymbolic_expr @@ -68,13 +71,13 @@ def pymbolic_trialfunction(ma): @symbol -def name_testfunctionspace(): - return "lfsv" +def name_testfunctionspace(restriction): + return restricted_name("lfsv", restriction) @symbol -def name_trialfunctionspace(): - return "lfsu" +def name_trialfunctionspace(restriction): + return restricted_name("lfsu", restriction) @symbol @@ -88,8 +91,8 @@ def type_trialfunctionspace(): @symbol -def name_coefficientcontainer(): - return "x" +def name_coefficientcontainer(restriction): + return restricted_name("x", restriction) @symbol @@ -98,10 +101,15 @@ def type_coefficientcontainer(): def name_argumentspace(ma): - if ma.argexpr.number() == 0: - return name_testfunctionspace(ma) - if ma.argexpr.number() == 1: - return name_trialfunctionspace(ma) + from ufl.classes import Argument, Coefficient + if isinstance(ma.argexpr, Argument): + if ma.argexpr.number() == 0: + return name_testfunctionspace(ma.restriction) + if ma.argexpr.number() == 1: + return name_trialfunctionspace(ma.restriction) + if isinstance(ma.argexpr, Coefficient): + assert ma.argexpr.count() == 0 + return name_trialfunctionspace(ma.restriction) # We should never encounter an argument other than 0 or 1 assert False @@ -124,8 +132,12 @@ def pymbolic_argument(ma): @symbol -def name_jacobian(): - return "jac" +def name_jacobian(restriction1, restriction2): + # Restrictions may only differ if NONE + if (restriction1 == Restriction.NONE) or (restriction2 == Restriction.NONE): + assert restriction1 == restriction2 + + return restricted_name(restricted_name("jac", restriction1), restriction2) @symbol @@ -134,8 +146,8 @@ def type_jacobian(): @symbol -def name_residual(): - return "r" +def name_residual(restriction): + return restricted_name("r", restriction) @symbol @@ -143,13 +155,13 @@ def type_residual(): return "R" -def name_accumulation_variable(): +def name_accumulation_variable(restrictions=(Restriction.NONE,)): from dune.perftool.generation import get_global_context_value ft = get_global_context_value("form_type") if ft == 'residual': - return name_residual() + return name_residual(*restrictions) if ft == 'jacobian': - return name_jacobian() + return name_jacobian(*restrictions) assert False diff --git a/python/dune/perftool/pdelab/basis.py b/python/dune/perftool/pdelab/basis.py index b8d5a07c..38cb06a6 100644 --- a/python/dune/perftool/pdelab/basis.py +++ b/python/dune/perftool/pdelab/basis.py @@ -22,6 +22,7 @@ from dune.perftool.pdelab.localoperator import (lop_template_ansatz_gfs, lop_template_test_gfs, ) from dune.perftool.pdelab.driver import FEM_name_mangling +from dune.perftool.pdelab import restricted_name @symbol @@ -114,27 +115,10 @@ def traverse_lfs_tree(arg): # First we need to determine the basename as given in the signature of # this kernel method! - lfs_basename = None - gfs_basename = None - from ufl.classes import Argument, Coefficient - if isinstance(arg.argexpr, Argument): - if arg.argexpr.count() == 0: - lfs_basename = 'lfsv' - gfs_basename = 'GFSV' - if arg.argexpr.count() == 1: - lfs_basename = 'lfsu' - gfs_basename = 'GFSU' - # TODO add restrictions here. - - if isinstance(arg.argexpr, Coefficient): - # We should only ever call this for a trialfunction, which in our case - # is the coefficient of reserved index 0. - assert arg.argexpr.count() == 0 - - lfs_basename = 'lfsu' - gfs_basename = 'GFSU' - - assert lfs_basename and gfs_basename + from dune.perftool.pdelab.argument import name_argumentspace + lfs_basename = name_argumentspace(arg) + from dune.perftool.pdelab.localoperator import lop_template_gfs + gfs_basename = lop_template_gfs(arg)[1] # Now start recursively extracting local function spaces and fill the cache with # all those values. That way we can later get a correct local function space with @@ -144,13 +128,10 @@ def traverse_lfs_tree(arg): @iname -def _lfs_iname(element, argcount, context): +def _lfs_iname(element, context): name = name_lfs(element) bound = name_lfs_bound(name) - if argcount != 0: - name = 'lfsu' - if context: context = '_' + context @@ -160,7 +141,7 @@ def _lfs_iname(element, argcount, context): return name -def lfs_iname(element, argcount=0, context=''): +def lfs_iname(element, context=''): """ Get the iname to iterate over the local function space given by element Arguments: @@ -174,7 +155,7 @@ def lfs_iname(element, argcount=0, context=''): a given purpose, see the 'Loops and dependencies' of the loopy docs: https://documen.tician.de/loopy/tutorial.html#loops-and-dependencies """ - return _lfs_iname(element, argcount, context) + return _lfs_iname(element, context) @preamble @@ -188,12 +169,12 @@ def declare_cache_temporary(element, name, which): @cached -def evaluate_basis(element, name): +def evaluate_basis(element, name, restriction): temporary_variable(name, shape=(name_lfs_bound(element),), decl_method=None) declare_cache_temporary(element, name, which='Function') cache = name_localbasis_cache(element) lfs = name_lfs(element) - qp = name_quadrature_position_in_cell() + qp = name_quadrature_position_in_cell(restriction) instruction(inames=(quadrature_iname(), ), code='{} = {}.evaluateFunction({}, {}.finiteElement().localBasis());'.format(name, @@ -207,18 +188,19 @@ def evaluate_basis(element, name): @symbol -def name_basis(element): - evaluate_basis(element, "phi") - return "phi" +def name_basis(element, restriction): + name = restricted_name("phi", restriction) + evaluate_basis(element, name, restriction) + return name @cached -def evaluate_reference_gradient(element, name): +def evaluate_reference_gradient(element, name, restriction): temporary_variable(name, shape=(name_lfs_bound(element), name_dimension()), decl_method=None) declare_cache_temporary(element, name, which='Jacobian') cache = name_localbasis_cache(element) lfs = name_lfs(element) - qp = name_quadrature_position_in_cell() + qp = name_quadrature_position_in_cell(restriction) instruction(inames=(quadrature_iname(), ), code='{} = {}.evaluateJacobian({}, {}.finiteElement().localBasis());'.format(name, @@ -232,18 +214,18 @@ def evaluate_reference_gradient(element, name): @symbol -def name_reference_gradient(element): - evaluate_reference_gradient(element, "js") - return "js" +def name_reference_gradient(element, restriction): + name = restricted_name("js", restriction) + evaluate_reference_gradient(element, name, restriction) + return name @cached -def evaluate_basis_gradient(element, name): - # TODO this is of course not yet correct +def evaluate_basis_gradient(element, name, restriction): temporary_variable(name, shape=(name_lfs_bound(element), name_dimension()), shape_impl=('vec', 'fv')) - jac = name_jacobian_inverse_transposed() + jac = name_jacobian_inverse_transposed(restriction) index = lfs_iname(element, context='transformgrads') - reference_gradients = name_reference_gradient(element) + reference_gradients = name_reference_gradient(element, restriction) instruction(inames=(index, quadrature_iname(), ), @@ -259,28 +241,42 @@ def evaluate_basis_gradient(element, name): @symbol -def name_basis_gradient(element): - evaluate_basis_gradient(element, "gradphi") - return "gradphi" +def name_basis_gradient(element, restriction): + name = restricted_name("gradphi", restriction) + evaluate_basis_gradient(element, name, restriction) + return name + + +def reset_trialfunction(name): + return instruction(inames=(quadrature_iname(), + ), + code="{} = 0.0;".format(name), + assignees=frozenset({name}), + ) @cached -def evaluate_trialfunction(element, name): +def evaluate_trialfunction(element, name, restriction): temporary_variable(name, shape=()) + reset = reset_trialfunction(name) lfs = name_lfs(element) index = lfs_iname(element) - basis = name_basis(element) + basis = name_basis(element, restriction) + from dune.perftool.pdelab.argument import name_coefficientcontainer + coeffs = name_coefficientcontainer(restriction) instruction(inames=(quadrature_iname(), index, ), - code='{} += x({}, {})*{}[{}];'.format(name, - lfs, - index, - basis, - index - ), + code='{} += {}({}, {})*{}[{}];'.format(name, + coeffs, + lfs, + index, + basis, + index + ), assignees=frozenset({name}), read_variables=frozenset({basis}), + depends_on=frozenset({reset}), ) @@ -293,22 +289,25 @@ def reset_trialfunction_gradient(name): @cached -def evaluate_trialfunction_gradient(element, name): +def evaluate_trialfunction_gradient(element, name, restriction): # TODO this is of course not yet correct temporary_variable(name, shape=(name_dimension(),), shape_impl=('fv',)) reset = reset_trialfunction_gradient(name) lfs = name_lfs(element) index = lfs_iname(element, context='trialgrad') - basis = name_basis_gradient(element) + basis = name_basis_gradient(element, restriction) + from dune.perftool.pdelab.argument import name_coefficientcontainer + coeffs = name_coefficientcontainer(restriction) instruction(inames=(quadrature_iname(), index, ), - code='{}.axpy(x({}, {}), {}[{}]);'.format(name, - lfs, - index, - basis, - index, - ), + code='{}.axpy({}({}, {}), {}[{}]);'.format(name, + coeffs, + lfs, + index, + basis, + index, + ), assignees=frozenset({name}), read_variables=frozenset({basis}), forced_iname_deps=frozenset({quadrature_iname(), index}), diff --git a/python/dune/perftool/pdelab/driver.py b/python/dune/perftool/pdelab/driver.py index 56dfb860..d8d69a50 100644 --- a/python/dune/perftool/pdelab/driver.py +++ b/python/dune/perftool/pdelab/driver.py @@ -263,7 +263,7 @@ def typedef_fem(expr, name): return "typedef Dune::PDELab::QkDGLocalFiniteElementMap<{}, {}, {}, {}> {}".format(df, r, expr._degree, dim, name) if isSimplical(expr): include_file("dune/pdelab/finiteelementmap/opbfem.hh", filetag="driver") - return "typedef Dune::PDELab::OPBLocalFiniteElementMap<{}, {}, {}, {}, Dune::GeometryType::cube> {}".format(df, r, expr._degree, dim, name) + return "typedef Dune::PDELab::OPBLocalFiniteElementMap<{}, {}, {}, {}, Dune::GeometryType::cube> {};".format(df, r, expr._degree, dim, name) raise NotImplementedError("Geometry type not known in code generation") raise NotImplementedError("FEM not implemented in dune-perftool") diff --git a/python/dune/perftool/pdelab/geometry.py b/python/dune/perftool/pdelab/geometry.py index 4bbfa6d5..1cdd8d62 100644 --- a/python/dune/perftool/pdelab/geometry.py +++ b/python/dune/perftool/pdelab/geometry.py @@ -1,9 +1,11 @@ from dune.perftool import Restriction +from dune.perftool.pdelab import restricted_name from dune.perftool.generation import (preamble, symbol, temporary_variable, ) from dune.perftool.pdelab.quadrature import (name_quadrature_position, + name_quadrature_position_in_cell, quadrature_preamble, ) from ufl.algorithms import MultiFunction @@ -94,43 +96,40 @@ def define_restricted_cell(name, restriction): @symbol -def _name_cell(restriction): +def name_cell(restriction): if restriction == Restriction.NONE: eg = name_element_geometry_wrapper() return "{}.entity()".format(eg) - - which = "inside" if restriction == Restriction.NEGATIVE else "outside" - name = "cell_{}".format(which) - define_restricted_cell(name, restriction) - return name - - -def name_cell(): - from dune.perftool.generation import get_global_context_value - it = get_global_context_value("integral_type") - - if it == 'cell': - r = Restriction.NONE - if it == 'exterior_facet': - r = Restriction.NEGATIVE - if it == 'interior_facet': - raise NotImplementedError - - return _name_cell(r) + else: + which = "inside" if restriction == Restriction.NEGATIVE else "outside" + name = "{}_cell".format(which) + define_restricted_cell(name, restriction) + return name @preamble -def define_cell_geometry(name): - eg = name_element_geometry_wrapper() +def define_cell_geometry(name, restriction): + cell = name_cell(restriction) return "auto {} = {}.geometry();".format(name, - eg + cell ) @symbol -def name_cell_geometry(): - define_cell_geometry("cell_geo") - return "cell_geo" +def name_cell_geometry(restriction): + name = restricted_name("cell_geo", restriction) + define_cell_geometry(name, restriction) + return name + + +@symbol +def type_cell_geometry(restriction): + if restriction == Restriction.NONE: + eg = type_element_geometry_wrapper() + return "{}::Geometry".format(eg) + else: + ig = type_intersection_geometry_wrapper() + return "{}::Entity::Geometry".format(ig) @preamble @@ -159,7 +158,7 @@ def name_geometry(): it = get_global_context_value("integral_type") if it == 'cell': - return name_cell_geometry() + return name_cell_geometry(Restriction.NONE) if it == 'exterior_facet' or it == 'interior_facet': return name_intersection_geometry() assert False @@ -167,7 +166,6 @@ def name_geometry(): @preamble def define_in_cell_geometry(restriction, name): - cell = _name_cell(restriction) ig = name_intersection_geometry_wrapper() which = "In" if restriction == Restriction.NEGATIVE else "Out" return "auto {} = {}.geometryIn{}side();".format(name, @@ -203,16 +201,10 @@ def name_in_cell_coordinates(local, basename, restriction): return name -def to_cell_coordinates(local, basename): - from dune.perftool.generation import get_global_context_value - it = get_global_context_value("integral_type") - - if it == 'cell': +def to_cell_coordinates(local, basename, restriction): + if restriction == Restriction.NONE: return local - if it == 'exterior_facet': - return name_in_cell_coordinates(local, basename, Restriction.NEGATIVE) - if it == 'interior_facet': - restriction = get_global_context_value("restriction") + else: return name_in_cell_coordinates(local, basename, restriction) @@ -267,24 +259,26 @@ def name_unit_inner_normal(): @symbol -def type_jacobian_inverse_transposed(): - geo = type_element_geometry_wrapper() - return "typename {}::Geometry::JacobianInverseTransposed".format(geo) +def type_jacobian_inverse_transposed(restriction): + geo = type_cell_geometry(restriction) + return "typename {}::JacobianInverseTransposed".format(geo) -@preamble -def define_jacobian_inverse_transposed_temporary(name, shape, shape_impl): - t = type_jacobian_inverse_transposed() - return "{} {};".format(t, - name, - ) +def define_jacobian_inverse_transposed_temporary(restriction): + @preamble + def _define_jacobian_inverse_transposed_temporary(name, shape, shape_impl): + t = type_jacobian_inverse_transposed(restriction) + return "{} {};".format(t, + name, + ) + return _define_jacobian_inverse_transposed_temporary -def define_jacobian_inverse_transposed(name): +def define_jacobian_inverse_transposed(name, restriction): dim = name_dimension() - temporary_variable(name, decl_method=define_jacobian_inverse_transposed_temporary, shape=(dim, dim)) - geo = name_cell_geometry() - pos = name_quadrature_position() + 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) return quadrature_preamble("{} = {}.jacobianInverseTransposed({});".format(name, geo, pos, @@ -294,6 +288,7 @@ def define_jacobian_inverse_transposed(name): @symbol -def name_jacobian_inverse_transposed(): - define_jacobian_inverse_transposed("jit") - return "jit" +def name_jacobian_inverse_transposed(restriction): + name = restricted_name("jit", restriction) + define_jacobian_inverse_transposed(name, restriction) + return name diff --git a/python/dune/perftool/pdelab/localoperator.py b/python/dune/perftool/pdelab/localoperator.py index 90555510..97e1f7e1 100644 --- a/python/dune/perftool/pdelab/localoperator.py +++ b/python/dune/perftool/pdelab/localoperator.py @@ -15,7 +15,7 @@ from dune.perftool.cgen.clazz import (AccessModifier, BaseClass, ClassMember, ) - +from dune.perftool import Restriction from pytools import memoize @@ -29,6 +29,14 @@ def lop_template_test_gfs(): return "GFSV" +def lop_template_gfs(ma): + if ma.argexpr.count() == 0: + return lop_template_test_gfs() + if ma.argexpr.count() == 1: + return lop_template_ansatz_gfs() + assert False + + @symbol def name_initree_constructor_param(): return "iniParams" @@ -116,56 +124,29 @@ def assembly_routine_signature(): integral_type = get_global_context_value("integral_type") form_type = get_global_context_value("form_type") - aj = "alpha" if form_type == 'residual' else "jacobian" - which = ufl_measure_to_pdelab_measure(integral_type).lower() - - if integral_type == 'interior_facet': - raise NotImplementedError - - from dune.perftool.pdelab.geometry import (name_geometry_wrapper, - type_geometry_wrapper, - ) - geot = type_geometry_wrapper() - geo = name_geometry_wrapper() - - from dune.perftool.pdelab.argument import (name_accumulation_variable, - type_accumulation_variable, - name_coefficientcontainer, - type_coefficientcontainer, - name_testfunctionspace, - type_testfunctionspace, - name_trialfunctionspace, - type_trialfunctionspace, - ) - lfsut = type_trialfunctionspace() - lfsu = name_trialfunctionspace() - lfsvt = type_testfunctionspace() - lfsv = name_testfunctionspace() - cct = type_coefficientcontainer() - cc = name_coefficientcontainer() - avt = type_accumulation_variable() - av = name_accumulation_variable() - - return ['template<typename {}, typename {}, typename {}, typename {}, typename {}>'.format(geot, - lfsut, - cct, - lfsvt, - avt, - ), - 'void {}_{}(const {}& {}, const {}& {}, const {}& {}, const {}& {}, {}& {}) const'.format(aj, - which, - geot, - geo, - lfsut, - lfsu, - cct, - cc, - lfsvt, - lfsv, - avt, - av, - ) - ] + if form_type == 'residual': + if integral_type == 'cell': + from dune.perftool.pdelab.signatures import alpha_volume_signature + return alpha_volume_signature() + if integral_type == 'exterior_facet': + from dune.perftool.pdelab.signatures import alpha_boundary_signature + return alpha_boundary_signature() + if integral_type == 'interior_facet': + from dune.perftool.pdelab.signatures import alpha_skeleton_signature + return alpha_skeleton_signature() + + if form_type == 'jacobian': + if integral_type == 'cell': + from dune.perftool.pdelab.signatures import jacobian_volume_signature + return jacobian_volume_signature() + if integral_type == 'exterior_facet': + from dune.perftool.pdelab.signatures import jacobian_boundary_signature + return jacobian_boundary_signature() + if integral_type == 'interior_facet': + from dune.perftool.pdelab.signatures import jacobian_skeleton_signature + return jacobian_skeleton_signature() + + assert False def generate_kernel(integral): diff --git a/python/dune/perftool/pdelab/parameter.py b/python/dune/perftool/pdelab/parameter.py index dc717063..abffb46d 100644 --- a/python/dune/perftool/pdelab/parameter.py +++ b/python/dune/perftool/pdelab/parameter.py @@ -62,10 +62,10 @@ def define_parameter_function_class_member(name, expr, t, cell): return result -def evaluate_cell_parameter_function(name): +def evaluate_cell_parameter_function(name, restriction): param = name_paramclass() - entity = name_cell() - pos = name_quadrature_position_in_cell() + entity = name_cell(restriction) + pos = name_quadrature_position_in_cell(restriction) return quadrature_preamble('{} = {}.{}({}, {});'.format(name, name_paramclass(), name, @@ -105,10 +105,10 @@ def define_parameter_temporary(t): return _define -def cell_parameter_function(name, expr, t='double'): +def cell_parameter_function(name, expr, restriction, t='double'): temporary_variable(name, shape=(), decl_method=define_parameter_temporary(t)) define_parameter_function_class_member(name, expr, t, True) - evaluate_cell_parameter_function(name) + evaluate_cell_parameter_function(name, restriction) def intersection_parameter_function(name, expr, t='double'): diff --git a/python/dune/perftool/pdelab/quadrature.py b/python/dune/perftool/pdelab/quadrature.py index 2e717f76..a874c923 100644 --- a/python/dune/perftool/pdelab/quadrature.py +++ b/python/dune/perftool/pdelab/quadrature.py @@ -30,9 +30,9 @@ def name_quadrature_position(): @symbol -def name_quadrature_position_in_cell(): +def name_quadrature_position_in_cell(restriction): from dune.perftool.pdelab.geometry import to_cell_coordinates - return to_cell_coordinates(name_quadrature_position(), name_quadrature_point()) + return to_cell_coordinates(name_quadrature_position(), name_quadrature_point(), restriction) @symbol diff --git a/python/dune/perftool/pdelab/signatures.py b/python/dune/perftool/pdelab/signatures.py new file mode 100644 index 00000000..b0e02593 --- /dev/null +++ b/python/dune/perftool/pdelab/signatures.py @@ -0,0 +1,238 @@ +""" Signatures for PDELab local opreator assembly functions """ + +from dune.perftool import Restriction +from dune.perftool.generation import symbol +from dune.perftool.pdelab.geometry import (name_geometry_wrapper, + type_geometry_wrapper, + ) +from dune.perftool.pdelab.argument import (name_accumulation_variable, + type_accumulation_variable, + name_coefficientcontainer, + type_coefficientcontainer, + name_testfunctionspace, + type_testfunctionspace, + name_trialfunctionspace, + type_trialfunctionspace, + ) + + +@symbol +def alpha_volume_signature(): + geot = type_geometry_wrapper() + geo = name_geometry_wrapper() + lfsut = type_trialfunctionspace() + lfsu = name_trialfunctionspace(Restriction.NONE) + lfsvt = type_testfunctionspace() + lfsv = name_testfunctionspace(Restriction.NONE) + cct = type_coefficientcontainer() + cc = name_coefficientcontainer(Restriction.NONE) + avt = type_accumulation_variable() + av = name_accumulation_variable((Restriction.NONE,)) + return ['template<typename {}, typename {}, typename {}, typename {}, typename {}>'.format(geot, + lfsut, + cct, + lfsvt, + avt, + ), + 'void alpha_volume(const {}& {}, const {}& {}, const {}& {}, const {}& {}, {}& {}) const'.format(geot, + geo, + lfsut, + lfsu, + cct, + cc, + lfsvt, + lfsv, + avt, + av, + ) + ] + + +@symbol +def alpha_boundary_signature(): + geot = type_geometry_wrapper() + geo = name_geometry_wrapper() + lfsut = type_trialfunctionspace() + lfsu = name_trialfunctionspace(Restriction.NEGATIVE) + lfsvt = type_testfunctionspace() + lfsv = name_testfunctionspace(Restriction.NEGATIVE) + cct = type_coefficientcontainer() + cc = name_coefficientcontainer(Restriction.NEGATIVE) + avt = type_accumulation_variable() + av = name_accumulation_variable((Restriction.NEGATIVE,)) + return ['template<typename {}, typename {}, typename {}, typename {}, typename {}>'.format(geot, + lfsut, + cct, + lfsvt, + avt, + ), + 'void alpha_boundary(const {}& {}, const {}& {}, const {}& {}, const {}& {}, {}& {}) const'.format(geot, + geo, + lfsut, + lfsu, + cct, + cc, + lfsvt, + lfsv, + avt, + av, + ) + ] + + +@symbol +def alpha_skeleton_signature(): + geot = type_geometry_wrapper() + geo = name_geometry_wrapper() + lfsut = type_trialfunctionspace() + lfsu_s = name_trialfunctionspace(Restriction.NEGATIVE) + lfsu_n = name_trialfunctionspace(Restriction.POSITIVE) + lfsvt = type_testfunctionspace() + lfsv_s = name_testfunctionspace(Restriction.NEGATIVE) + lfsv_n = name_testfunctionspace(Restriction.POSITIVE) + cct = type_coefficientcontainer() + cc_s = name_coefficientcontainer(Restriction.NEGATIVE) + cc_n = name_coefficientcontainer(Restriction.POSITIVE) + avt = type_accumulation_variable() + av_s = name_accumulation_variable((Restriction.NEGATIVE,)) + av_n = name_accumulation_variable((Restriction.POSITIVE,)) + return ['template<typename {}, typename {}, typename {}, typename {}, typename {}>'.format(geot, + lfsut, + cct, + lfsvt, + avt, + ), + 'void alpha_skeleton(const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, {}& {}, {}& {}) const'.format(geot, + geo, + lfsut, + lfsu_s, + cct, + cc_s, + lfsvt, + lfsv_s, + lfsut, + lfsu_n, + cct, + cc_n, + lfsvt, + lfsv_n, + avt, + av_s, + avt, + av_n, + ) + ] + + +@symbol +def jacobian_volume_signature(): + geot = type_geometry_wrapper() + geo = name_geometry_wrapper() + lfsut = type_trialfunctionspace() + lfsu = name_trialfunctionspace(Restriction.NONE) + lfsvt = type_testfunctionspace() + lfsv = name_testfunctionspace(Restriction.NONE) + cct = type_coefficientcontainer() + cc = name_coefficientcontainer(Restriction.NONE) + avt = type_accumulation_variable() + av = name_accumulation_variable((Restriction.NONE, Restriction.NONE)) + return ['template<typename {}, typename {}, typename {}, typename {}, typename {}>'.format(geot, + lfsut, + cct, + lfsvt, + avt, + ), + 'void jacobian_volume(const {}& {}, const {}& {}, const {}& {}, const {}& {}, {}& {}) const'.format(geot, + geo, + lfsut, + lfsu, + cct, + cc, + lfsvt, + lfsv, + avt, + av, + ) + ] + + +@symbol +def jacobian_boundary_signature(): + geot = type_geometry_wrapper() + geo = name_geometry_wrapper() + lfsut = type_trialfunctionspace() + lfsu = name_trialfunctionspace(Restriction.NEGATIVE) + lfsvt = type_testfunctionspace() + lfsv = name_testfunctionspace(Restriction.NEGATIVE) + cct = type_coefficientcontainer() + cc = name_coefficientcontainer(Restriction.NEGATIVE) + avt = type_accumulation_variable() + av = name_accumulation_variable((Restriction.NEGATIVE, Restriction.NEGATIVE)) + return ['template<typename {}, typename {}, typename {}, typename {}, typename {}>'.format(geot, + lfsut, + cct, + lfsvt, + avt, + ), + 'void jacobian_boundary(const {}& {}, const {}& {}, const {}& {}, const {}& {}, {}& {}) const'.format(geot, + geo, + lfsut, + lfsu, + cct, + cc, + lfsvt, + lfsv, + avt, + av, + ) + ] + + +@symbol +def jacobian_skeleton_signature(): + geot = type_geometry_wrapper() + geo = name_geometry_wrapper() + lfsut = type_trialfunctionspace() + lfsu_s = name_trialfunctionspace(Restriction.NEGATIVE) + lfsu_n = name_trialfunctionspace(Restriction.POSITIVE) + lfsvt = type_testfunctionspace() + lfsv_s = name_testfunctionspace(Restriction.NEGATIVE) + lfsv_n = name_testfunctionspace(Restriction.POSITIVE) + cct = type_coefficientcontainer() + cc_s = name_coefficientcontainer(Restriction.NEGATIVE) + cc_n = name_coefficientcontainer(Restriction.POSITIVE) + avt = type_accumulation_variable() + av_ss = name_accumulation_variable((Restriction.NEGATIVE, Restriction.NEGATIVE)) + av_sn = name_accumulation_variable((Restriction.NEGATIVE, Restriction.POSITIVE)) + av_ns = name_accumulation_variable((Restriction.POSITIVE, Restriction.NEGATIVE)) + av_nn = name_accumulation_variable((Restriction.POSITIVE, Restriction.POSITIVE)) + return ['template<typename {}, typename {}, typename {}, typename {}, typename {}>'.format(geot, + lfsut, + cct, + lfsvt, + avt, + ), + 'void jacobian_skeleton(const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, {}& {}, {}& {}, {}& {}, {}& {}) const'.format(geot, + geo, + lfsut, + lfsu_s, + cct, + cc_s, + lfsvt, + lfsv_s, + lfsut, + lfsu_n, + cct, + cc_n, + lfsvt, + lfsv_n, + avt, + av_ss, + avt, + av_sn, + avt, + av_ns, + avt, + av_nn, + ) + ] diff --git a/python/dune/perftool/pymbolic/uflmapper.py b/python/dune/perftool/pymbolic/uflmapper.py index 854c4762..19d6f250 100644 --- a/python/dune/perftool/pymbolic/uflmapper.py +++ b/python/dune/perftool/pymbolic/uflmapper.py @@ -58,3 +58,6 @@ class UFL2PymbolicMapper(MultiFunction): def sum(self, o): return Sum(tuple(self.call(op) for op in get_operands(o))) + + def zero(self, o): + return 0 diff --git a/test/laplace/CMakeLists.txt b/test/laplace/CMakeLists.txt index e268854d..ae7f7d55 100644 --- a/test/laplace/CMakeLists.txt +++ b/test/laplace/CMakeLists.txt @@ -22,3 +22,10 @@ add_generated_executable(UFLFILE laplace_dg.ufl dune_add_system_test(TARGET laplace_dg_numdiff INIFILE laplace_dg_numdiff.mini) + +add_generated_executable(UFLFILE laplace_dg.ufl + TARGET laplace_dg_symdiff + ) + +dune_add_system_test(TARGET laplace_dg_symdiff + INIFILE laplace_dg_symdiff.mini) diff --git a/test/laplace/laplace_dg_numdiff.mini b/test/laplace/laplace_dg_numdiff.mini index bf8ddc7a..ad527212 100644 --- a/test/laplace/laplace_dg_numdiff.mini +++ b/test/laplace/laplace_dg_numdiff.mini @@ -1,4 +1,4 @@ -__name = laplacg_dg_numdiff +__name = laplace_dg_numdiff lowerleft = 0.0 0.0 upperright = 1.0 1.0 diff --git a/test/laplace/laplace_dg_symdiff.mini b/test/laplace/laplace_dg_symdiff.mini new file mode 100644 index 00000000..edefa9db --- /dev/null +++ b/test/laplace/laplace_dg_symdiff.mini @@ -0,0 +1,6 @@ +__name = laplace_dg_symdiff + +lowerleft = 0.0 0.0 +upperright = 1.0 1.0 +elements = 4 4 +elementType = simplical -- GitLab