diff --git a/python/dune/perftool/pdelab/driver/error.py b/python/dune/perftool/pdelab/driver/error.py index dbbb0b9c4f13327e26a48f8ef8f87f1e1cf75693..6e7fb9128e5437650baf140191311ee4a02eb5f7 100644 --- a/python/dune/perftool/pdelab/driver/error.py +++ b/python/dune/perftool/pdelab/driver/error.py @@ -9,13 +9,18 @@ from dune.perftool.pdelab.driver import (get_formdata, get_trial_element, preprocess_leaf_data, ) -from dune.perftool.pdelab.driver.gridfunctionspace import name_gfs +from dune.perftool.pdelab.driver.gridfunctionspace import (name_trial_gfs, + name_trial_subgfs, + type_range, + ) from dune.perftool.pdelab.driver.interpolate import (interpolate_vector, name_boundary_function, ) from dune.perftool.pdelab.driver.solve import (define_vector, + dune_solve, name_vector, ) +from ufl import MixedElement, TensorElement, VectorElement @preamble @@ -29,43 +34,18 @@ def name_test_fail_variable(): return name -def name_exact_solution(): - name = "solution" - define_vector(name, get_formdata()) - interpolate_exact_solution(name) - return name - - -def interpolate_exact_solution(name): +def name_exact_solution_gridfunction(treepath): element = get_trial_element() - is_dirichlet = preprocess_leaf_data(element, "is_dirichlet") - gfs = name_gfs(element, is_dirichlet) - sol = preprocess_leaf_data(element, "exact_solution") - func = name_boundary_function(element, sol) - interpolate_vector(func, gfs, name) - - -@preamble -def compare_dofs(): - v = name_vector(get_formdata()) - solution = name_exact_solution() - fail = name_test_fail_variable() - - return ["", - "// Maximum norm of difference between dof vectors of the", - "// numerical solution and the interpolation of the exact solution", - "using Dune::PDELab::Backend::native;", - "double maxerror(0.0);", - "for (std::size_t i=0; i<native({}).size(); ++i)".format(v), - " if (std::abs(native({})[i]-native({})[i]) > maxerror)".format(v, solution), - " maxerror = std::abs(native({})[i]-native({})[i]);".format(v, solution), - "std::cout << std::endl << \"Maxerror: \" << maxerror << std::endl;", - "if (maxerror>{})".format(get_option("compare_dofs")), - " {} = true;".format(fail)] + func = preprocess_leaf_data(element, "exact_solution") + if isinstance(element, MixedElement): + index = treepath_to_index(element, treepath) + func = (func[index],) + element = element.extract_component(index)[1] + return name_boundary_function(element, func) def type_discrete_grid_function(gfs): - return "DGF_{}".format(gfs.upper()) + return "{}_DGF".format(gfs.upper()) @preamble @@ -82,53 +62,93 @@ def name_discrete_grid_function(gfs, vector_name): @preamble -def typedef_difference_squared_adapter(name): - sol = name_exact_solution() +def typedef_difference_squared_adapter(name, treepath): + sol = name_exact_solution_gridfunction(treepath) vector = name_vector(get_formdata()) + gfs = name_trial_subgfs(treepath) dgf = name_discrete_grid_function(gfs, vector) return 'using {} = Dune::PDELab::DifferenceSquaredAdapter<decltype({}), decltype({})>;'.format(name, sol, dgf) -def type_difference_squared_adapter(): - name = 'DifferenceSquaredAdapter' - typedef_difference_squared_adapter(name) +def type_difference_squared_adapter(treepath): + name = 'DifferenceSquaredAdapter_{}'.format("_".join(str(t) for t in treepath)) + typedef_difference_squared_adapter(name, treepath) return name @preamble -def define_difference_squared_adapter(name): - t = type_difference_squared_adapter() - sol = name_exact_solution() +def define_difference_squared_adapter(name, treepath): + t = type_difference_squared_adapter(treepath) + sol = name_exact_solution_gridfunction(treepath) vector = name_vector(get_formdata()) + gfs = name_trial_subgfs(treepath) dgf = name_discrete_grid_function(gfs, vector) return '{} {}({}, {});'.format(t, name, sol, dgf) -def name_difference_squared_adapter(): - name = 'differencesquared_adapter' - define_difference_squared_adapter(name) +def name_difference_squared_adapter(treepath): + name = 'dsa_{}'.format("_".join(str(t) for t in treepath)) + define_difference_squared_adapter(name, treepath) return name @preamble -def accumulate_L2_squared(): - dsa = name_difference_squared_adapter() +def _accumulate_L2_squared(treepath): + dsa = name_difference_squared_adapter(treepath) accum_error = name_accumulated_L2_error() 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", - " Dune::PDELab::integrateGridFunction({}, {}, 10);".format(dsa, accum_error), + strtp = ", ".join(str(t) for t in treepath) + + return ["{", + " // L2 error squared of difference between numerical", + " // solution and the interpolation of exact solution", + " // for treepath ({})".format(strtp), + " typename decltype({})::Traits::RangeType err(0.0);".format(dsa), + " Dune::PDELab::integrateGridFunction({}, err, 10);".format(dsa), + " {} += err;".format(accum_error), + " std::cout << \"L2 Error for treepath {}: \" << err << std::endl;".format(strtp), + "}", ] +def get_treepath(element, index): + if isinstance(element, (VectorElement, TensorElement)): + return (index,) + if isinstance(element, MixedElement): + pos, rest = element.extract_subelement_component(index) + offset = sum(element.sub_elements()[i].value_size() for i in range(pos)) + return (pos,) + get_treepath(element.sub_elements()[pos], index - offset) + else: + return () + + +def treepath_to_index(element, treepath, offset=0): + if len(treepath) == 0: + return offset + index = treepath[0] + offset = offset + sum(element.sub_elements()[i].value_size() for i in range(index)) + subel = element.sub_elements()[index] + return treepath_to_index(subel, treepath[1:], offset) + + +def accumulate_L2_squared(): + element = get_trial_element() + if isinstance(element, MixedElement): + for i in range(element.value_size()): + _accumulate_L2_squared(get_treepath(element, i)) + else: + _accumulate_L2_squared(()) + + @preamble def define_accumulated_L2_error(name): - return "double {}(0.0);".format(name) + t = type_range() + return "{} {}(0.0);".format(t, name) def name_accumulated_L2_error(): @@ -143,8 +163,10 @@ def compare_L2_squared(): accum_error = name_accumulated_L2_error() fail = name_test_fail_variable() - return ["std::cout << \"l2errorsquared: \" << {} << std::endl;".format(accum_error), - "if (std::isnan({0}) or std::abs({0})>{1})".format(accum_error, get_option("compare_l2errorsquared")), + return ["using std::abs;", + "using std::isnan;", + "std::cout << \"\\nl2errorsquared: \" << {} << std::endl << std::endl;".format(accum_error), + "if (isnan({0}) or abs({0})>{1})".format(accum_error, get_option("compare_l2errorsquared")), " {} = true;".format(fail)] diff --git a/python/dune/perftool/pdelab/driver/gridfunctionspace.py b/python/dune/perftool/pdelab/driver/gridfunctionspace.py index b439ded1b1465dd87fa839329a7238505409c7e5..2ab2234736db0d761efa1b1dfb29298d2b815983 100644 --- a/python/dune/perftool/pdelab/driver/gridfunctionspace.py +++ b/python/dune/perftool/pdelab/driver/gridfunctionspace.py @@ -175,27 +175,30 @@ def name_test_gfs(): return name_gfs(element, is_dirichlet) -def name_gfs(element, is_dirichlet): +def name_gfs(element, is_dirichlet, treepath=()): if isinstance(element, (VectorElement, TensorElement)): - subel = element.sub_element()[0] - subgfs = name_gfs(subel, is_dirichlet[:subel.value_size()]) - name = "{}_pow{}gfs".format(subgfs, element.num_sub_elements()) + subel = element.sub_elements()[0] + subgfs = name_gfs(subel, is_dirichlet[:subel.value_size()], treepath=treepath + (0,)) + name = "{}_pow{}gfs_{}".format(subgfs, + element.num_sub_elements(), + "_".join(str(t) for t in treepath)) define_power_gfs(element, is_dirichlet, name, subgfs) return name if isinstance(element, MixedElement): k = 0 subgfs = [] - for subel in element.sub_elements(): - subgfs.append(name_gfs(subel, is_dirichlet[k:k + subel.value_size()])) + for i, subel in enumerate(element.sub_elements()): + subgfs.append(name_gfs(subel, is_dirichlet[k:k + subel.value_size()], treepath=treepath + (i,))) k = k + subel.value_size() name = "_".join(subgfs) - define_composite_gfs(element, is_dirichlet, name, subgfs) + name = "{}_{}".format(name, "_".join(str(t) for t in treepath)) + define_composite_gfs(element, is_dirichlet, name, tuple(subgfs)) return name else: assert isinstance(element, FiniteElement) - name = "{}{}_gfs".format(FEM_name_mangling(element).lower(), - "_dirichlet" if is_dirichlet else "", - ) + name = "{}{}_gfs_{}".format(FEM_name_mangling(element).lower(), + "_dirichlet" if is_dirichlet[0] else "", + "_".join(str(t) for t in treepath)) define_gfs(element, is_dirichlet, name) return name @@ -214,7 +217,7 @@ def type_trial_gfs(): def type_gfs(element, is_dirichlet): if isinstance(element, (VectorElement, TensorElement)): - subel = element.sub_element()[0] + subel = element.sub_elements()[0] subgfs = type_gfs(subel, is_dirichlet[:subel.value_size()]) name = "{}_POW{}GFS".format(subgfs, element.num_sub_elements()) typedef_power_gfs(element, is_dirichlet, name, subgfs) @@ -226,12 +229,12 @@ def type_gfs(element, is_dirichlet): subgfs.append(type_gfs(subel, is_dirichlet[k:k + subel.value_size()])) k = k + subel.value_size() name = "_".join(subgfs) - typedef_composite_gfs(element, name, subgfs) + typedef_composite_gfs(element, name, tuple(subgfs)) return name else: assert isinstance(element, FiniteElement) name = "{}{}_GFS".format(FEM_name_mangling(element).upper(), - "_dirichlet" if is_dirichlet else "", + "_dirichlet" if is_dirichlet[0] else "", ) typedef_gfs(element, is_dirichlet, name) return name @@ -242,13 +245,15 @@ def define_gfs(element, is_dirichlet, name): gfstype = type_gfs(element, is_dirichlet) gv = name_leafview() fem = name_fem(element) - return "{} {}({}, {});".format(gfstype, name, gv, fem) + return ["{} {}({}, {});".format(gfstype, name, gv, fem), + "{}.name(\"{}\");".format(name, name)] @preamble def define_power_gfs(element, is_dirichlet, name, subgfs): gv = name_leafview() fem = name_fem(element.sub_elements()[0]) + gfstype = type_gfs(element, is_dirichlet) return "{} {}({}, {});".format(gfstype, name, gv, fem) @@ -263,7 +268,7 @@ def typedef_gfs(element, is_dirichlet, name): vb = type_vectorbackend(element) gv = type_leafview() fem = type_fem(element) - cass = type_constraintsassembler(bool(is_dirichlet)) + cass = type_constraintsassembler(bool(is_dirichlet[0])) return "using {} = Dune::PDELab::GridFunctionSpace<{}, {}, {}, {}>;".format(name, gv, fem, cass, vb) @@ -343,3 +348,30 @@ def type_constraintsassembler(is_dirichlet): name = "NoConstraintsAssembler" typedef_no_constraintsassembler(name) return name + + +def name_trial_subgfs(treepath): + if len(treepath) == 0: + return name_trial_gfs() + else: + return name_subgfs(treepath) + + +def name_subgfs(treepath): + gfs = name_trial_gfs() + name = "{}_{}".format(gfs, "_".join(str(t) for t in treepath)) + define_subgfs(name, treepath) + return name + + +@preamble +def define_subgfs(name, treepath): + t = type_subgfs(treepath) + gfs = name_trial_gfs() + return "{} {}({});".format(t, name, gfs) + + +def type_subgfs(tree_path): + include_file('dune/pdelab/gridfunctionspace/subspace.hh', filetag='driver') + gfs = type_trial_gfs() + return "Dune::PDELab::GridFunctionSubSpace<{}, Dune::TypeTree::TreePath<{}> >".format(gfs, ', '.join(str(t) for t in tree_path)) diff --git a/python/dune/perftool/pdelab/driver/instationary.py b/python/dune/perftool/pdelab/driver/instationary.py index 7cefddb50d6a5cb2907c228dd328acbdc1db6170..4d8064d6286edf6b5ed59f6bea46832ea093ea1e 100644 --- a/python/dune/perftool/pdelab/driver/instationary.py +++ b/python/dune/perftool/pdelab/driver/instationary.py @@ -1,11 +1,35 @@ -from dune.perftool.generation import preamble +from dune.perftool.generation import (include_file, + preamble, + ) from dune.perftool.pdelab.driver import (get_formdata, + get_mass_formdata, + get_trial_element, is_linear, + name_initree, + preprocess_leaf_data, ) -from dune.perftool.pdelab.driver.gridoperator import (type_gridoperator,) +from dune.perftool.pdelab.driver.gridfunctionspace import (name_trial_gfs, + type_range, + ) +from dune.perftool.pdelab.driver.gridoperator import (name_gridoperator, + name_parameters, + type_gridoperator,) +from dune.perftool.pdelab.driver.constraints import (name_bctype_function, + name_constraintscontainer, + ) +from dune.perftool.pdelab.driver.interpolate import (interpolate_dirichlet_data, + name_boundary_function, + ) from dune.perftool.pdelab.driver.solve import (print_matrix, print_residual, + name_stationarynonlinearproblemsolver, + name_vector, + type_stationarynonlinearproblemssolver, + type_vector, ) +from dune.perftool.pdelab.driver.vtk import (name_vtk_sequence_writer, + visualize_initial_condition, + ) from dune.perftool.options import get_option @@ -28,12 +52,6 @@ def solve_instationary(): print_residual() print_matrix() - from dune.perftool.pdelab.driver.error import compare_dofs, compare_L2_squared - if get_option("exact_solution_expression"): - if get_option("compare_dofs"): - compare_dofs() - if get_option("compare_l2errorsquared"): - compare_L2_squared() @preamble @@ -42,12 +60,14 @@ def time_loop(): formdata = get_formdata() params = name_parameters(formdata) time = name_time() - expr = get_trial_element() - bctype = name_bctype_function(expr) - gfs = name_gfs(expr) - cc = name_constraintscontainer(expr) + element = get_trial_element() + is_dirichlet = preprocess_leaf_data(element, "is_dirichlet") + bctype = name_bctype_function(element, is_dirichlet) + gfs = name_trial_gfs() + cc = name_constraintscontainer() vector_type = type_vector(formdata) vector = name_vector(formdata) + interpolate_dirichlet_data(vector) # Choose between explicit and implicit time stepping explicit = get_option('explicit_time_stepping') @@ -55,7 +75,8 @@ def time_loop(): osm = name_explicitonestepmethod() apply_call = "{}.apply(time, dt, {}, {}new);".format(osm, vector, vector) else: - boundary = name_boundary_function(expr) + dirichlet = preprocess_leaf_data(element, "dirichlet_expression") + boundary = name_boundary_function(element, dirichlet) osm = name_onestepmethod() apply_call = "{}.apply(time, dt, {}, {}, {}new);".format(osm, vector, boundary, vector) @@ -95,7 +116,6 @@ def name_time(): return "time" - @preamble def typedef_timesteppingmethod(name): r_type = type_range() @@ -131,8 +151,8 @@ def name_timesteppingmethod(): @preamble def typedef_instationarygridoperator(name): include_file("dune/pdelab/gridoperator/onestep.hh", filetag="driver") - go_type = type_gridoperator(_driver_data['formdata']) - mass_go_type = type_gridoperator(_driver_data['mass_formdata']) + go_type = type_gridoperator(get_formdata()) + mass_go_type = type_gridoperator(get_mass_formdata()) explicit = get_option('explicit_time_stepping') if explicit: return "using {} = Dune::PDELab::OneStepGridOperator<{},{},false>;".format(name, go_type, mass_go_type) @@ -148,8 +168,8 @@ def type_instationarygridoperator(): @preamble def define_instationarygridoperator(name): igo_type = type_instationarygridoperator() - go = name_gridoperator(_driver_data['formdata']) - mass_go = name_gridoperator(_driver_data['mass_formdata']) + go = name_gridoperator(get_formdata()) + mass_go = name_gridoperator(get_mass_formdata()) return "{} {}({}, {});".format(igo_type, name, go, mass_go) @@ -163,7 +183,7 @@ def typedef_onestepmethod(name): r_type = type_range() igo_type = type_instationarygridoperator() snp_type = type_stationarynonlinearproblemssolver(igo_type) - vector_type = type_vector(_driver_data['formdata']) + vector_type = type_vector(get_formdata()) return "using {} = Dune::PDELab::OneStepMethod<{}, {}, {}, {}, {}>;".format(name, r_type, igo_type, snp_type, vector_type, vector_type) @@ -192,7 +212,7 @@ def typedef_explicitonestepmethod(name): r_type = type_range() igo_type = type_instationarygridoperator() ls_type = type_linearsolver() - vector_type = type_vector(_driver_data['formdata']) + vector_type = type_vector(get_formdata()) return "using {} = Dune::PDELab::ExplicitOneStepMethod<{}, {}, {}, {}>;".format(name, r_type, igo_type, ls_type, vector_type) diff --git a/python/dune/perftool/pdelab/driver/interpolate.py b/python/dune/perftool/pdelab/driver/interpolate.py index 626896c11e68495ab0337ea5bcde5a8a993f4a57..3e92f4b9e839f9986829af4967e862b81c612dbc 100644 --- a/python/dune/perftool/pdelab/driver/interpolate.py +++ b/python/dune/perftool/pdelab/driver/interpolate.py @@ -10,7 +10,7 @@ from dune.perftool.pdelab.driver import (FEM_name_mangling, is_stationary, preprocess_leaf_data, ) -from dune.perftool.pdelab.driver.gridfunctionspace import (name_gfs, +from dune.perftool.pdelab.driver.gridfunctionspace import (name_trial_gfs, name_leafview, ) from dune.perftool.pdelab.driver.gridoperator import (name_parameters,) @@ -28,8 +28,8 @@ def _do_interpolate(dirichlet): def interpolate_dirichlet_data(name): element = get_trial_element() is_dirichlet = preprocess_leaf_data(element, "is_dirichlet") - if _do_interpolate(is_dirichlet): - gfs = name_gfs(element, is_dirichlet) + if _do_interpolate(is_dirichlet) or not is_stationary(): + gfs = name_trial_gfs() dirichlet = preprocess_leaf_data(element, "dirichlet_expression") bf = name_boundary_function(element, dirichlet) interpolate_vector(bf, gfs, name) diff --git a/python/dune/perftool/pdelab/driver/vtk.py b/python/dune/perftool/pdelab/driver/vtk.py index 15c39c3d22f2a7542c0c08e59cc8ac1c9838ab31..a4adbff493351b7530833bea708114a3257beb5a 100644 --- a/python/dune/perftool/pdelab/driver/vtk.py +++ b/python/dune/perftool/pdelab/driver/vtk.py @@ -122,7 +122,6 @@ def visualize_initial_condition(): include_file("dune/pdelab/gridfunctionspace/vtk.hh", filetag="driver") vtkwriter = name_vtk_sequence_writer() element = get_trial_element() - define_gfs_names(element) gfs = name_trial_gfs() vector = name_vector(get_formdata()) predicate = name_predicate() @@ -130,23 +129,3 @@ def visualize_initial_condition(): time = name_time() return ["Dune::PDELab::addSolutionToVTKWriter({}, {}, {}, Dune::PDELab::vtk::defaultNameScheme(), {});".format(vtkwriter, gfs, vector, predicate), "{}.write({}, Dune::VTK::appendedraw);".format(vtkwriter, time)] - - -@preamble -def _define_gfs_name(element, is_dirichlet, offset=0): - from ufl import MixedElement - if isinstance(element, MixedElement): - k = 0 - for subel in element.sub_elements(): - define_gfs_name(subel, is_dirichlet[k:k + subel.value_size()], offset=offset + k) - k = k + subel.value_size() - return [] - else: - # This is a scalar leaf - gfs = name_gfs(element, is_dirichlet) - return "{}.name(\"data_{}\");".format(gfs, offset) - - -def define_gfs_names(element): - is_dirichlet = preprocess_leaf_data(element, "is_dirichlet") - return _define_gfs_name(element, is_dirichlet) \ No newline at end of file