From 5b0942d4036a2abae836c1068d23fee60521e9e6 Mon Sep 17 00:00:00 2001 From: Dominic Kempf <dominic.kempf@iwr.uni-heidelberg.de> Date: Tue, 26 Apr 2016 15:06:23 +0200 Subject: [PATCH] Work poisson_neumann_numdiff example! --- python/dune/perftool/__init__.py | 4 +- python/dune/perftool/loopy/transformer.py | 18 +- python/dune/perftool/pdelab/argument.py | 56 +++++- python/dune/perftool/pdelab/basis.py | 9 +- python/dune/perftool/pdelab/driver.py | 10 +- python/dune/perftool/pdelab/geometry.py | 173 +++++++++++++++++-- python/dune/perftool/pdelab/localoperator.py | 59 +++++-- python/dune/perftool/pdelab/parameter.py | 67 +++++-- python/dune/perftool/pdelab/quadrature.py | 7 +- python/dune/perftool/ufl/execution.py | 3 +- test/poisson/CMakeLists.txt | 1 + test/poisson/poisson_neumann.ufl | 4 +- 12 files changed, 352 insertions(+), 59 deletions(-) diff --git a/python/dune/perftool/__init__.py b/python/dune/perftool/__init__.py index 175c0adc..eb279cf1 100644 --- a/python/dune/perftool/__init__.py +++ b/python/dune/perftool/__init__.py @@ -1,4 +1,4 @@ class Restriction: NONE = 0 - POSITIVE = 1 - NEGATIVE = 2 + INSIDE = 1 + OUTSIDE = 2 diff --git a/python/dune/perftool/loopy/transformer.py b/python/dune/perftool/loopy/transformer.py index 6776df96..21c2265d 100644 --- a/python/dune/perftool/loopy/transformer.py +++ b/python/dune/perftool/loopy/transformer.py @@ -48,8 +48,13 @@ class UFL2LoopyVisitor(ModifiedTerminalTracker, UFL2PymbolicMapper): name = get_global_context_value("namedata")[id(o)] # Trigger the generation of code for this thing in the parameter class - from dune.perftool.pdelab.parameter import parameter_function - parameter_function(name, o) + from dune.perftool.pdelab.parameter import (cell_parameter_function, + intersection_parameter_function, + ) + if o.on_intersection: + intersection_parameter_function(name, o) + else: + cell_parameter_function(name, o) # And return a symbol from pymbolic.primitives import Variable @@ -151,8 +156,9 @@ def transform_accumulation_term(term, measure, subdomain_id): # Generate the code for the modified arguments: for arg in test_ma: - from dune.perftool.pdelab.argument import name_argumentspace, pymbolic_argument - accumargs.append(name_argumentspace(arg)) + 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())) # Determine the shape @@ -215,8 +221,8 @@ def transform_accumulation_term(term, measure, subdomain_id): name = get_global_context_value("namedata")[id(subdomain_data)] # Trigger the generation of code for this thing in the parameter class - from dune.perftool.pdelab.parameter import parameter_function - parameter_function(name, subdomain_data, t='int') + from dune.perftool.pdelab.parameter import intersection_parameter_function + intersection_parameter_function(name, subdomain_data, t='int') code = "if ({} == {})\n {}".format(name, subdomain_id, code) diff --git a/python/dune/perftool/pdelab/argument.py b/python/dune/perftool/pdelab/argument.py index 86e1ccba..3ea5c1d8 100644 --- a/python/dune/perftool/pdelab/argument.py +++ b/python/dune/perftool/pdelab/argument.py @@ -68,17 +68,35 @@ def pymbolic_trialfunction(ma): @symbol -def name_testfunctionspace(*a): - # TODO +def name_testfunctionspace(): return "lfsv" @symbol -def name_trialfunctionspace(*a): - # TODO +def name_trialfunctionspace(): return "lfsu" +@symbol +def type_testfunctionspace(): + return "LFSV" + + +@symbol +def type_trialfunctionspace(): + return "LFSU" + + +@symbol +def name_coefficientcontainer(): + return "x" + + +@symbol +def type_coefficientcontainer(): + return "X" + + def name_argumentspace(ma): if ma.argexpr.number() == 0: return name_testfunctionspace(ma) @@ -110,6 +128,36 @@ def name_jacobian(): return "jac" +@symbol +def type_jacobian(): + return "J" + + @symbol def name_residual(): return "r" + + +@symbol +def type_residual(): + return "R" + + +def name_accumulation_variable(): + from dune.perftool.generation import get_global_context_value + ft = get_global_context_value("form_type") + if ft == 'residual': + return name_residual() + if ft == 'jacobian': + return name_jacobian() + assert False + + +def type_accumulation_variable(): + from dune.perftool.generation import get_global_context_value + ft = get_global_context_value("form_type") + if ft == 'residual': + return type_residual() + if ft == 'jacobian': + return type_jacobian() + assert False diff --git a/python/dune/perftool/pdelab/basis.py b/python/dune/perftool/pdelab/basis.py index f8f7484e..2015ac73 100644 --- a/python/dune/perftool/pdelab/basis.py +++ b/python/dune/perftool/pdelab/basis.py @@ -11,11 +11,12 @@ from dune.perftool.generation import (cached, symbol, temporary_variable, ) -from dune.perftool.pdelab.quadrature import (name_quadrature_position, +from dune.perftool.pdelab.quadrature import (name_quadrature_position_in_cell, quadrature_iname, ) from dune.perftool.pdelab.geometry import (name_dimension, name_jacobian_inverse_transposed, + to_cell_coordinates, ) from dune.perftool.pdelab.localoperator import (lop_template_ansatz_gfs, lop_template_test_gfs, @@ -192,7 +193,7 @@ def evaluate_basis(element, name): declare_cache_temporary(element, name, which='Function') cache = name_localbasis_cache(element) lfs = name_lfs(element) - qp = name_quadrature_position() + qp = name_quadrature_position_in_cell() instruction(inames=(quadrature_iname(), ), code='{} = {}.evaluateFunction({}, {}.finiteElement().localBasis());'.format(name, @@ -201,6 +202,7 @@ def evaluate_basis(element, name): lfs, ), assignees=frozenset({name}), + read_variables=frozenset({qp}), ) @@ -216,7 +218,7 @@ def evaluate_reference_gradient(element, name): declare_cache_temporary(element, name, which='Jacobian') cache = name_localbasis_cache(element) lfs = name_lfs(element) - qp = name_quadrature_position() + qp = name_quadrature_position_in_cell() instruction(inames=(quadrature_iname(), ), code='{} = {}.evaluateJacobian({}, {}.finiteElement().localBasis());'.format(name, @@ -225,6 +227,7 @@ def evaluate_reference_gradient(element, name): lfs, ), assignees=frozenset({name}), + read_variables=frozenset({qp}), ) diff --git a/python/dune/perftool/pdelab/driver.py b/python/dune/perftool/pdelab/driver.py index e5c25af6..556fbfb8 100644 --- a/python/dune/perftool/pdelab/driver.py +++ b/python/dune/perftool/pdelab/driver.py @@ -339,7 +339,10 @@ def name_constraintscontainer(element, dirichlet): @preamble def define_intersection_lambda(expression, name): - return "auto {} = [&](const auto& is, const auto& x){{ {} }};".format(name, expression.c_expr) + if expression.is_global: + return "auto {} = [&](const auto& x){{ {} }};".format(name, expression.c_expr) + else: + return "auto {} = [&](const auto& is, const auto& x){{ {} }};".format(name, expression.c_expr) @symbol @@ -601,7 +604,10 @@ def define_vector(name): @preamble def define_boundary_lambda(boundary, name): - return "auto {} = [&](const auto& x){{ {} }};".format(name, boundary.c_expr) + if boundary.is_global: + return "auto {} = [&](const auto& x){{ {} }};".format(name, boundary.c_expr) + else: + return "auto {} = [&](const auto& e, const auto& x){{ {} }};".format(name, boundary.c_expr) @symbol diff --git a/python/dune/perftool/pdelab/geometry.py b/python/dune/perftool/pdelab/geometry.py index bc42d0af..4e0f5ab6 100644 --- a/python/dune/perftool/pdelab/geometry.py +++ b/python/dune/perftool/pdelab/geometry.py @@ -1,3 +1,4 @@ +from dune.perftool import Restriction from dune.perftool.generation import (preamble, symbol, temporary_variable, @@ -8,38 +9,184 @@ from dune.perftool.pdelab.quadrature import (name_quadrature_position, @symbol -def name_entitygeometry(): +def name_element_geometry_wrapper(): return 'eg' @symbol -def name_entity(): - eg = name_entitygeometry() - return "{}.entity()".format(eg) +def type_element_geometry_wrapper(): + return 'EG' + + +@symbol +def name_intersection_geometry_wrapper(): + return 'ig' + + +@symbol +def type_intersection_geometry_wrapper(): + return 'IG' + + +def name_geometry_wrapper(): + """ Selects the 'native' geometry wrapper of the kernel """ + from dune.perftool.generation import get_global_context_value + it = get_global_context_value("integral_type") + + if it == 'cell': + return name_element_geometry_wrapper() + if it == 'exterior_facet' or it == 'interior_facet': + return name_intersection_geometry_wrapper() + assert False + + +def type_geometry_wrapper(): + """ Selects the 'native' geometry wrapper of the kernel """ + from dune.perftool.generation import get_global_context_value + it = get_global_context_value("integral_type") + + if it == 'cell': + return type_element_geometry_wrapper() + if it == 'exterior_facet' or it == 'interior_facet': + return type_intersection_geometry_wrapper() + assert False @preamble -def define_geometry(name): - eg = name_entitygeometry() +def define_restricted_cell(name, restriction): + ig = name_intersection_geometry_wrapper() + which = "inside" if restriction == Restriction.INSIDE else "outside" + return "const auto& {} = {}.{}();".format(name, + ig, + which, + ) + + +@symbol +def _name_cell(restriction): + if restriction == Restriction.NONE: + eg = name_element_geometry_wrapper() + return "{}.entity()".format(eg) + + which = "inside" if restriction == Restriction.INSIDE 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.INSIDE + if it == 'interior_facet': + raise NotImplementedError + + return _name_cell(r) + + +@preamble +def define_cell_geometry(name): + eg = name_element_geometry_wrapper() return "auto {} = {}.geometry();".format(name, eg ) @symbol +def name_cell_geometry(): + define_cell_geometry("cell_geo") + return "cell_geo" + + +@preamble +def define_intersection_geometry(name): + ig = name_intersection_geometry_wrapper() + return "auto {} = {}.geometry();".format(name, + ig, + ) + + +@symbol +def name_intersection_geometry(): + define_intersection_geometry("is_geo") + return "is_geo" + + +@symbol +def name_intersection(): + ig = name_intersection_geometry_wrapper() + return "{}.intersection()".format(ig) + + def name_geometry(): - define_geometry("geo") - return "geo" + """ Selects the 'native' geometry of the kernel """ + from dune.perftool.generation import get_global_context_value + it = get_global_context_value("integral_type") + + if it == 'cell': + return name_cell_geometry() + if it == 'exterior_facet' or it == 'interior_facet': + return name_intersection_geometry() + assert False + + +@preamble +def define_in_cell_geometry(restriction, name): + cell = _name_cell(restriction) + ig = name_intersection_geometry_wrapper() + which = "In" if restriction == Restriction.INSIDE else "Out" + return "auto {} = {}.geometryIn{}side();".format(name, + ig, + which + ) @symbol -def type_geometry(): - return 'EG' +def name_in_cell_geometry(restriction): + assert restriction is not Restriction.NONE + + name = "geo_in_{}side".format("in" if restriction is Restriction.INSIDE else "out") + define_in_cell_geometry(restriction, name) + return name + + +def apply_in_cell_transformation(name, local, restriction): + geo = name_in_cell_geometry(restriction) + return quadrature_preamble("{} = {}.global({});".format(name, + geo, + local, + ), + assignees=name, + ) + + +@symbol +def name_in_cell_coordinates(local, basename, restriction): + name = "{}_in_inside".format(basename) + temporary_variable(name, shape=(name_dimension(),), shape_impl=("fv",)) + apply_in_cell_transformation(name, local, restriction=Restriction.INSIDE) + 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': + return local + if it == 'exterior_facet': + return name_in_cell_coordinates(local, basename, Restriction.INSIDE) + if it == 'interior_facet': + raise NotImplementedError @preamble def define_dimension(name): - geo = type_geometry() + geo = type_geometry_wrapper() return 'const int {} = {}::Entity::dimension;'.format(name, geo) @@ -51,7 +198,7 @@ def name_dimension(): @symbol def type_jacobian_inverse_transposed(): - geo = type_geometry() + geo = type_element_geometry_wrapper() return "typename {}::Geometry::JacobianInverseTransposed".format(geo) @@ -66,7 +213,7 @@ def define_jacobian_inverse_transposed_temporary(name, shape, shape_impl): def define_jacobian_inverse_transposed(name): dim = name_dimension() temporary_variable(name, decl_method=define_jacobian_inverse_transposed_temporary, shape=(dim, dim)) - geo = name_geometry() + geo = name_cell_geometry() pos = name_quadrature_position() return quadrature_preamble("{} = {}.jacobianInverseTransposed({});".format(name, geo, diff --git a/python/dune/perftool/pdelab/localoperator.py b/python/dune/perftool/pdelab/localoperator.py index 3301357b..370ef617 100644 --- a/python/dune/perftool/pdelab/localoperator.py +++ b/python/dune/perftool/pdelab/localoperator.py @@ -117,20 +117,55 @@ def assembly_routine_signature(): form_type = get_global_context_value("form_type") aj = "alpha" if form_type == 'residual' else "jacobian" - - if integral_type == 'cell': - return ['template<typename EG, typename LFSU, typename X, typename LFSV, typename R>', - 'void {}_volume(const EG& eg, const LFSU& lfsu, const X& x, const LFSV& lfsv, R& r) const'.format(aj)] - - if integral_type == 'exterior_facet': - return ['template<typename IG, typename LFSV0, typename X, typename LFSV1, typename R>', - 'void {}_boundary(const IG& ig, const LFSV0& lfsv0, const X& x, const LFSV1& lfsv1, R& r) const'.format(aj)] + which = ufl_measure_to_pdelab_measure(integral_type).lower() if integral_type == 'interior_facet': - return ['template<typename IG, typename LFSV0_S, typename X, typename LFSV1_S, typename LFSV0_N, typename R, typename LFSV1_N>', - 'void {}_skeleton(const IG& ig, const LFSV0_S& lfsv0_s, const X& x_s, const LFSV1_S& lfsv1_s, const LFSV0_N& lfsv0_n, const X& x_n, const LFSV1_N& lfsv1_n, R& r_s, R& r_n) const'.format(aj)] - - assert False + 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, + ) + ] def generate_kernel(integral): diff --git a/python/dune/perftool/pdelab/parameter.py b/python/dune/perftool/pdelab/parameter.py index 9b4885d3..dc717063 100644 --- a/python/dune/perftool/pdelab/parameter.py +++ b/python/dune/perftool/pdelab/parameter.py @@ -5,11 +5,15 @@ from dune.perftool.generation import (class_basename, constructor_parameter, generator_factory, initializer_list, + preamble, symbol, temporary_variable ) -from dune.perftool.pdelab.geometry import name_entity +from dune.perftool.pdelab.geometry import (name_cell, + name_intersection, + ) from dune.perftool.pdelab.quadrature import (name_quadrature_position, + name_quadrature_position_in_cell, quadrature_preamble, ) from dune.perftool.cgen.clazz import AccessModifier @@ -39,14 +43,16 @@ def name_paramclass(): @class_member("parameterclass", access=AccessModifier.PUBLIC) -def define_parameter_function_class_member(name, expr, t): - result = ["template<typename E, typename X>", - "{} {}(const E& e, const X& local) const".format(t, name), +def define_parameter_function_class_member(name, expr, t, cell): + geot = "E" if cell else "I" + geo = geot.lower() + result = ["template<typename {}, typename X>".format(geot), + "{} {}(const {}& {}, const X& local) const".format(t, name, geot, geo), "{", ] if expr.is_global: - result.append(" auto x = e.geometry().global(local);") + result.append(" auto x = {}.geometry().global(local);".format(geo)) else: result.append(" auto x = local;") @@ -56,21 +62,56 @@ def define_parameter_function_class_member(name, expr, t): return result -def evaluate_parameter_function(name): +def evaluate_cell_parameter_function(name): param = name_paramclass() - entity = name_entity() - pos = name_quadrature_position() + entity = name_cell() + pos = name_quadrature_position_in_cell() return quadrature_preamble('{} = {}.{}({}, {});'.format(name, name_paramclass(), name, entity, pos, ), - assignees=frozenset({name}) + assignees=frozenset({name}), + read_variables=frozenset({pos}), + ) + + +def evaluate_intersection_parameter_function(name): + # Check that this is not a volume term, as that would not be well-defined + from dune.perftool.generation import get_global_context_value + it = get_global_context_value("integral_type") + assert it is not 'cell' + + param = name_paramclass() + intersection = name_intersection() + pos = name_quadrature_position() + return quadrature_preamble('{} = {}.{}({}, {});'.format(name, + name_paramclass(), + name, + intersection, + pos, + ), + assignees=frozenset({name}), + read_variables=frozenset({pos}), ) -def parameter_function(name, expr, t='double'): - temporary_variable(name, shape=()) - define_parameter_function_class_member(name, expr, t) - evaluate_parameter_function(name) +def define_parameter_temporary(t): + @preamble + def _define(name, shape, shape_impl): + assert len(shape) == 0 + return "{} {};".format(t, name) + return _define + + +def cell_parameter_function(name, expr, 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) + + +def intersection_parameter_function(name, expr, t='double'): + temporary_variable(name, shape=(), decl_method=define_parameter_temporary(t)) + define_parameter_function_class_member(name, expr, t, False) + evaluate_intersection_parameter_function(name) diff --git a/python/dune/perftool/pdelab/quadrature.py b/python/dune/perftool/pdelab/quadrature.py index b4555eef..2e717f76 100644 --- a/python/dune/perftool/pdelab/quadrature.py +++ b/python/dune/perftool/pdelab/quadrature.py @@ -29,6 +29,12 @@ def name_quadrature_position(): return "{}.position()".format(qp) +@symbol +def name_quadrature_position_in_cell(): + from dune.perftool.pdelab.geometry import to_cell_coordinates + return to_cell_coordinates(name_quadrature_position(), name_quadrature_point()) + + @symbol def name_quadrature_weight(): qp = name_quadrature_point() @@ -63,7 +69,6 @@ def name_order(): return "2" -@cached def quadrature_loop_statement(): include_file('dune/pdelab/common/quadraturerules.hh', filetag='operatorfile') qp = name_quadrature_point() diff --git a/python/dune/perftool/ufl/execution.py b/python/dune/perftool/ufl/execution.py index a3397c0a..28cacedc 100644 --- a/python/dune/perftool/ufl/execution.py +++ b/python/dune/perftool/ufl/execution.py @@ -48,10 +48,11 @@ _dg0 = FiniteElement("DG", "triangle", 0) class Expression(Coefficient): - def __init__(self, expr, is_global=True): + def __init__(self, expr, is_global=True, on_intersection=False): assert isinstance(expr, str) self.c_expr = expr self.is_global = is_global + self.on_intersection = on_intersection # Initialize a coefficient with a dummy finite element map. Coefficient.__init__(self, _dg0) diff --git a/test/poisson/CMakeLists.txt b/test/poisson/CMakeLists.txt index 2ccd6cce..c4e3a69d 100644 --- a/test/poisson/CMakeLists.txt +++ b/test/poisson/CMakeLists.txt @@ -31,4 +31,5 @@ add_generated_executable(UFLFILE poisson_neumann.ufl dune_add_system_test(TARGET poisson_neumann_numdiff INIFILE poisson.mini + SCRIPT dune_vtkcompare.py ) diff --git a/test/poisson/poisson_neumann.ufl b/test/poisson/poisson_neumann.ufl index 385a1bb8..e86bb53b 100644 --- a/test/poisson/poisson_neumann.ufl +++ b/test/poisson/poisson_neumann.ufl @@ -1,7 +1,7 @@ f = Expression("Dune::FieldVector<double,2> c(0.5); c-= x; return 4.*(1.-c.two_norm2())*std::exp(-1.*c.two_norm2());") g = Expression("Dune::FieldVector<double,2> c(0.5); c-= x; return std::exp(-1.*c.two_norm2());") -j = Expression("Dune::FieldVector<double,2> c(0.5); c-= x; double s; if (x[1]>0.5) s=1.; else s=-1.; return s*4*x[1]*c.two_norm2()*std::exp(-1.*c.two_norm2());") -bctype = Expression("if ((x[1]<1e-8) || (x[1]>1-1e-8)) return 0; else return 1;") +j = Expression("Dune::FieldVector<double,2> c(0.5); c-= x; double s; if (x[1]>0.5) s=1.; else s=-1.; return -2.*s*(x[1]-0.5)*std::exp(-1.*c.two_norm2());", on_intersection=True) +bctype = Expression("if ((x[1]<1e-8) || (x[1]>1.-1e-8)) return 0; else return 1;", on_intersection=True) V = FiniteElement("CG", "triangle", 1, dirichlet_expression=g, dirichlet_constraints=bctype) u = TrialFunction(V) -- GitLab