From fe1d653449535ff4d84438a6a3948b189588bb14 Mon Sep 17 00:00:00 2001 From: Dominic Kempf <dominic.kempf@iwr.uni-heidelberg.de> Date: Tue, 6 Sep 2016 17:40:42 +0200 Subject: [PATCH] Make l2 error comparison for systems possible --- python/dune/perftool/pdelab/driver.py | 170 ++++++++++++++++++++------ python/dune/perftool/ufl/execution.py | 10 +- test/stokes/CMakeLists.txt | 3 - test/stokes/stokes.mini | 2 + test/stokes/stokes_dg.mini | 2 + test/stokes/stokes_stress.mini | 2 + test/stokes/stokes_stress.ufl | 7 +- 7 files changed, 154 insertions(+), 42 deletions(-) diff --git a/python/dune/perftool/pdelab/driver.py b/python/dune/perftool/pdelab/driver.py index dfbaf7c4..917ea160 100644 --- a/python/dune/perftool/pdelab/driver.py +++ b/python/dune/perftool/pdelab/driver.py @@ -807,6 +807,7 @@ def _name_boundary_function(element, boundary, name=None): define_boundary_function(boundary, name) return name + def name_boundary_function(expr): # This is a scalar leaf of the ansatz function tree element, (_, boundary) = get_constraints_metadata(expr) @@ -814,17 +815,23 @@ def name_boundary_function(expr): return _name_boundary_function(element, boundary) - @symbol -def name_solution_function(expr): - # Get expression representing solution +def name_solution_function(tree_path=()): + from dune.perftool.generation import get_global_context_value + expr = get_global_context_value("data").object_by_name[get_option("exact_solution_expression")] + + from dune.perftool.ufl.execution import split_expression + for i in tree_path: + expr = split_expression(expr)[int(i)] + from dune.perftool.generation import get_global_context_value - solution_expression_name = get_option("exact_solution_expression") - solution_expression = get_global_context_value("data").object_by_name[solution_expression_name] + try: + name = get_global_context_value("data").object_names[id(expr)] + except KeyError: + from dune.perftool.generation.cache import _GlobalCounter + name = 'generic_{}'.format(_GlobalCounter().get()) - # Create function just like it is done for boundary_function - name = "solution_function" - define_boundary_function(solution_expression, name) + define_boundary_function(expr, name) return name @@ -846,7 +853,7 @@ def interpolate_solution_expression(name): formdata = _driver_data['formdata'] define_vector(name, formdata) element = _driver_data['form'].coefficients()[0].ufl_element() - sol = name_solution_function(element) + sol = name_solution_function() gfs = name_gfs(element) return "Dune::PDELab::interpolate({}, {}, {});".format(sol, gfs, @@ -1181,41 +1188,144 @@ def compare_dofs(): "if (maxerror>{})".format(get_option("compare_dofs")), " throw;"] +@symbol +def type_discrete_grid_function(gfs): + return "DGF_{}".format(gfs.upper()) + @preamble def define_discrete_grid_function(gfs, vector_name, dgf_name): - return ["typedef Dune::PDELab::DiscreteGridFunction<decltype({}),decltype({})> DGF;".format(gfs, vector_name), - "DGF {}({},{});".format(dgf_name, gfs, vector_name)] + dgf_type = type_discrete_grid_function(gfs) + return ["typedef Dune::PDELab::DiscreteGridFunction<decltype({}),decltype({})> {};".format(gfs, vector_name, dgf_type), + "{} {}({},{});".format(dgf_type, dgf_name, gfs, vector_name)] @symbol def name_discrete_grid_function(gfs, vector_name): - dgf_name = vector_name + "_dgf" + dgf_name = gfs + "_dgf" define_discrete_grid_function(gfs, vector_name, dgf_name) return dgf_name +@symbol +def type_subgfs(element, tree_path): + include_file('dune/pdelab/gridfunctionspace/subspace.hh', filetag='driver') + gfs = type_gfs(element) + return "Dune::PDELab::GridFunctionSubSpace<{}, Dune::TypeTree::TreePath<{}> >".format(gfs, ', '.join(tree_path)) + + @preamble -def compare_L2_squared(): +def define_subgfs(name, element, tree_path): + t = type_subgfs(element, tree_path) + gfs = name_gfs(element) + + return '{} {}({});'.format(t, name, gfs) + + +@symbol +def name_subgfs(element, tree_path): + gfs = name_gfs(element) + if len(tree_path) == 0: + return gfs + else: + name = "subgfs_{}_{}".format(gfs, '_'.join(tree_path)) + define_subgfs(name, element, tree_path) + return name + + +@preamble +def typedef_difference_squared_adapter(name, tree_path): element = _driver_data['form'].coefficients()[0].ufl_element() formdata = _driver_data['formdata'] - v = name_vector(formdata) - gfs = name_gfs(element) - vdgf = name_discrete_grid_function(gfs, v) - solution_function = name_solution_function(element) + + solution_function = name_solution_function(tree_path) + gfs = name_subgfs(element, tree_path) + vector = name_vector(formdata) + dgf = name_discrete_grid_function(gfs, vector) + + return 'typedef DifferenceSquaredAdapter<decltype({}), decltype({})> {};'.format(solution_function, dgf, name) + + +@symbol +def type_difference_squared_adapter(tree_path): + t = 'DifferenceSquared_{}'.format('_'.join(tree_path)) + typedef_difference_squared_adapter(t, tree_path) + return t + + +@preamble +def define_difference_squared_adapter(name, tree_path): + element = _driver_data['form'].coefficients()[0].ufl_element() + formdata = _driver_data['formdata'] + + t = type_difference_squared_adapter(tree_path) + solution_function = name_solution_function(tree_path) + gfs = name_subgfs(element, tree_path) + vector = name_vector(formdata) + dgf = name_discrete_grid_function(gfs, vector) + + return '{} {}({}, {});'.format(t, name, solution_function, dgf) + + +def name_difference_squared_adapter(tree_path): + name = 'differencesquared_{}'.format('_'.join(tree_path)) + define_difference_squared_adapter(name, tree_path) + return name + + +@preamble +def _accumulate_L2_squared(tree_path): + dsa = name_difference_squared_adapter(tree_path) + t_dsa = type_difference_squared_adapter(tree_path) + accum_error = name_accumulated_l2error() include_file("dune/pdelab/gridfunctionspace/gridfunctionadapter.hh", filetag="driver") include_file("dune/pdelab/common/functionutilities.hh", filetag="driver") - return ["", - "// L2 error squared of difference between numerical", - "// solution and the interpolation of exact solution", - "typedef DifferenceSquaredAdapter<decltype({}),decltype({})> DifferenceSquared;".format(solution_function, vdgf), - "DifferenceSquared differencesquared({},{});".format(solution_function, vdgf), - "typename DifferenceSquared::Traits::RangeType l2errorsquared(0.0);", - "Dune::PDELab::integrateGridFunction(differencesquared,l2errorsquared,10);", - "std::cout << \"l2errorsquared: \" << l2errorsquared << std::endl;", - "if (l2errorsquared>{})".format(get_option("compare_l2errorsquared")), + return ["{", + " // L2 error squared of difference between numerical", + " // solution and the interpolation of exact solution", + " // only subgfs with treepath: {}".format(', '.join(tree_path)), + " typename {}::Traits::RangeType err(0.0);".format(t_dsa), + " Dune::PDELab::integrateGridFunction({}, err, 10);".format(dsa), + " {} += err;".format(accum_error), + " std::cout << \"Accumlated L2 Error for tree path {}: \" << err << std::endl;".format(tree_path), + "}"] + + +def accumulate_L2_squared(tree_path=()): + element = _driver_data['form'].coefficients()[0].ufl_element() + from ufl.functionview import select_subelement + from ufl.classes import MultiIndex, FixedIndex + element = select_subelement(element, MultiIndex(tuple(FixedIndex(int(i)) for i in tree_path))) + + from ufl import MixedElement + if isinstance(element, MixedElement): + for i, subel in enumerate(element.sub_elements()): + accumulate_L2_squared(tree_path + (str(i),)) + else: + _accumulate_L2_squared(tree_path) + + +@preamble +def define_accumulated_l2error(name): + return "double {}(0.0);".format(name) + + +@symbol +def name_accumulated_l2error(): + name = 'l2error' + define_accumulated_l2error(name) + return name + + +@preamble +def compare_L2_squared(): + accumulate_L2_squared() + + accum_error = name_accumulated_l2error() + return ["std::cout << \"l2errorsquared: \" << {} << std::endl;".format(accum_error), + "if ({}>{})".format(accum_error, get_option("compare_l2errorsquared")), " throw;"] @@ -1302,10 +1412,6 @@ def vtkoutput(): print_matrix() if get_option("exact_solution_expression"): - from ufl import MixedElement, VectorElement, TensorElement - if isinstance(_driver_data['form'].coefficients()[0].ufl_element(), (MixedElement, VectorElement, TensorElement)): - raise NotImplementedError("Comparing to exact solution is olny implemented for scalar elements.") - if get_option("compare_dofs"): compare_dofs() if get_option("compare_l2errorsquared"): @@ -1437,10 +1543,6 @@ def solve_instationary(): print_residual() print_matrix() if get_option("exact_solution_expression"): - from ufl import MixedElement, VectorElement, TensorElement - if isinstance(_driver_data['form'].coefficients()[0].ufl_element(), (MixedElement, VectorElement, TensorElement)): - raise NotImplementedError("Comparing to exact solution is olny implemented for scalar elements.") - if get_option("compare_dofs"): compare_dofs() if get_option("compare_l2errorsquared"): diff --git a/python/dune/perftool/ufl/execution.py b/python/dune/perftool/ufl/execution.py index 8bce0a7b..a4b8043f 100644 --- a/python/dune/perftool/ufl/execution.py +++ b/python/dune/perftool/ufl/execution.py @@ -107,8 +107,14 @@ class Expression(Coefficient): def __mul__(self, other): # Allow the combination of Expressions if isinstance(other, Expression): - from ufl import MixedElement - return Expression(cppcode=self.c_expr + other.c_expr, element=self.element * other.element) + from ufl import MixedElement, TensorElement + def get_sub(elem): + if isinstance(elem, MixedElement) and not isinstance(elem, (VectorElement, TensorElement)): + return elem.sub_elements() + else: + return [elem] + newelem = MixedElement(*(get_sub(self.element) + get_sub(other.element))) + return Expression(cppcode=self.c_expr + other.c_expr, element=newelem) else: return Coefficient.__mul__(self, other) diff --git a/test/stokes/CMakeLists.txt b/test/stokes/CMakeLists.txt index 8d6fa96d..0d3751b8 100644 --- a/test/stokes/CMakeLists.txt +++ b/test/stokes/CMakeLists.txt @@ -5,17 +5,14 @@ dune_symlink_to_source_files(FILES hagenpoiseuille_ref.vtu dune_add_formcompiler_system_test(UFLFILE stokes.ufl BASENAME stokes INIFILE stokes.mini - SCRIPT dune_vtkcompare.py ) dune_add_formcompiler_system_test(UFLFILE stokes_dg.ufl BASENAME stokes_dg INIFILE stokes_dg.mini - SCRIPT dune_vtkcompare.py ) dune_add_formcompiler_system_test(UFLFILE stokes_stress.ufl BASENAME stokes_stress INIFILE stokes_stress.mini - SCRIPT dune_vtkcompare.py ) diff --git a/test/stokes/stokes.mini b/test/stokes/stokes.mini index 23a79329..6bb834ff 100644 --- a/test/stokes/stokes.mini +++ b/test/stokes/stokes.mini @@ -14,3 +14,5 @@ extension = vtu [formcompiler] numerical_jacobian = 0, 1 | expand num +exact_solution_expression = g +compare_l2errorsquared = 1e-6 diff --git a/test/stokes/stokes_dg.mini b/test/stokes/stokes_dg.mini index 6448f4f5..20d92508 100644 --- a/test/stokes/stokes_dg.mini +++ b/test/stokes/stokes_dg.mini @@ -16,3 +16,5 @@ zeroThreshold.data_1 = 1e-6 [formcompiler] numerical_jacobian = 0, 1 | expand num +exact_solution_expression = g +compare_l2errorsquared = 1e-5 diff --git a/test/stokes/stokes_stress.mini b/test/stokes/stokes_stress.mini index 642ef6d2..4481e91d 100644 --- a/test/stokes/stokes_stress.mini +++ b/test/stokes/stokes_stress.mini @@ -14,3 +14,5 @@ extension = vtu [formcompiler] numerical_jacobian = 0, 1 | expand num +exact_solution_expression = g +compare_l2errorsquared = 1e-6 diff --git a/test/stokes/stokes_stress.ufl b/test/stokes/stokes_stress.ufl index 71a32399..d5c41e30 100644 --- a/test/stokes/stokes_stress.ufl +++ b/test/stokes/stokes_stress.ufl @@ -1,18 +1,19 @@ v_bctype = Expression("if (x[0] < 1. - 1e-8) return 1; else return 0;", on_intersection=True) g_v = Expression(("4*x[1]*(1.-x[1])", "0.0")) g_p = Expression("8*(1.-x[0])") -g = g_v * g_p +g_S = Expression(("0.0", "0.0", "-8*x[1] + 4.", "0.0")) +g = g_v * g_p * g_S cell = triangle P2 = VectorElement("Lagrange", cell, 2, dirichlet_constraints=v_bctype, dirichlet_expression=g_v) P1 = FiniteElement("Lagrange", cell, 1) -P2_stress = TensorElement("Lagrange", cell, 2) +P2_stress = TensorElement("DG", cell, 1) TH = MixedElement(P2, P1, P2_stress) v, q, T = TestFunctions(TH) u, p, S = TrialFunctions(TH) -r = (inner(grad(v), S) + inner(S - grad(u), T)- div(v)*p - q*div(u))*dx +r = (inner(grad(v), S) + inner(grad(u) - S, T) - div(v)*p - q*div(u))*dx forms = [r] -- GitLab