From 0868a1fd0ce89e058bfb99c06e175d0af87ab588 Mon Sep 17 00:00:00 2001 From: Dominic Kempf <dominic.kempf@iwr.uni-heidelberg.de> Date: Wed, 2 Aug 2017 14:09:50 +0200 Subject: [PATCH] Rewrite driver generation Do not annotate FiniteElements anymore, further split driver code --- .../dune/perftool/pdelab/driver/__init__.py | 1331 +---------------- .../perftool/pdelab/driver/constraints.py | 144 ++ python/dune/perftool/pdelab/driver/error.py | 195 +-- .../pdelab/driver/gridfunctionspace.py | 345 +++++ .../perftool/pdelab/driver/gridoperator.py | 173 +++ .../perftool/pdelab/driver/instationary.py | 213 +++ .../perftool/pdelab/driver/interpolate.py | 115 ++ python/dune/perftool/pdelab/driver/solve.py | 245 +++ python/dune/perftool/pdelab/driver/vtk.py | 151 ++ python/dune/perftool/ufl/execution.py | 58 - test/poisson/poisson.mini | 1 - test/poisson/poisson.ufl | 5 +- 12 files changed, 1503 insertions(+), 1473 deletions(-) create mode 100644 python/dune/perftool/pdelab/driver/constraints.py create mode 100644 python/dune/perftool/pdelab/driver/gridfunctionspace.py create mode 100644 python/dune/perftool/pdelab/driver/gridoperator.py create mode 100644 python/dune/perftool/pdelab/driver/instationary.py create mode 100644 python/dune/perftool/pdelab/driver/interpolate.py create mode 100644 python/dune/perftool/pdelab/driver/solve.py create mode 100644 python/dune/perftool/pdelab/driver/vtk.py diff --git a/python/dune/perftool/pdelab/driver/__init__.py b/python/dune/perftool/pdelab/driver/__init__.py index dcc3ec4a..c59330ce 100644 --- a/python/dune/perftool/pdelab/driver/__init__.py +++ b/python/dune/perftool/pdelab/driver/__init__.py @@ -47,6 +47,10 @@ def get_dimension(): return _driver_data['form'].ufl_cell().geometric_dimension() +def get_cell(): + return _driver_data['form'].ufl_cell().cellname() + + def get_test_element(): return _driver_data['form'].arguments()[0].ufl_element() @@ -70,29 +74,8 @@ def form_name_suffix(name, formdata): return name + '_' + form_name -def has_constraints(element): - from ufl import MixedElement, VectorElement - if isinstance(element, MixedElement) and not isinstance(element, VectorElement): - return any(has_constraints(el) for el in element.sub_elements()) - return hasattr(element, "dirichlet_constraints") - - -# Those symbol generators that depend on the meta data we hacked into -# the ufl.FiniteElement should use fem_metadata_dependent_symbol instead of symbol. -def get_constraints_metadata(element): - """ - Normally, we suppress the constraints information on a finite element. - However, we might want to use it explicitly in those case where it matters - This function does the job! - """ - dc = getattr(element, 'dirichlet_constraints', None) - de = getattr(element, 'dirichlet_expression', None) - return (element, (dc, de)) - - -fem_metadata_dependent_symbol = generator_factory(item_tags=("symbol",), - cache_key_generator=get_constraints_metadata, - ) +def get_object(name): + return _driver_data['data'].object_by_name.get(name, None) def mass_form_index(formdatas, data): @@ -104,8 +87,9 @@ def mass_form_index(formdatas, data): continue -def is_linear(form): - '''Test if form is linear in test function''' +def is_linear(): + '''Test if form is linear in trial function''' + form = get_formdata().original_form from ufl import derivative from ufl.algorithms import expand_derivatives jacform = expand_derivatives(derivative(form, form.coefficients()[0])) @@ -120,20 +104,26 @@ def isLagrange(fem): return fem._short_name is 'CG' -def isSimplical(fem): - return any(fem._cell._cellname in x for x in ["triangle", "tetrahedron"]) +def isSimplical(cell): + # Cells can be identified through strings *or* ufl objects + if not isinstance(cell, str): + cell = cell.cellname() + return cell in ["vertex", "interval", "triangle", "tetrahedron"] -def isQuadrilateral(fem): - return any(fem._cell._cellname in x for x in ["vertex", "interval", "quadrilateral", "hexahedron"]) +def isQuadrilateral(cell): + # Cells can be identified through strings *or* ufl objects + if not isinstance(cell, str): + cell = cell.cellname() + return cell in ["vertex", "interval", "quadrilateral", "hexahedron"] def isPk(fem): - return isLagrange(fem) and isSimplical(fem) + return isLagrange(fem) and isSimplical(fem.cell()) def isQk(fem): - return isLagrange(fem) and isQuadrilateral(fem) + return isLagrange(fem) and isQuadrilateral(fem.cell()) def isDG(fem): @@ -164,6 +154,40 @@ def FEM_name_mangling(fem): raise NotImplementedError("FEM NAME MANGLING") +def _flatten_list(l): + if isinstance(l, (tuple, list)): + for i in l: + for ni in _flatten_list(i): + yield ni + else: + yield l + + +def preprocess_leaf_data(element, data): + data = get_object(data) + from ufl import MixedElement + if isinstance(element, MixedElement): + # Dirichlet is None -> no dirichlet boundaries + if data is None: + return (0,) * element.value_size() + # Dirichlet for MixedElement is not iterable -> Same + # constraint on all the leafs. + elif not isinstance(data, (tuple, list)): + return (data,) * element.value_size() + # List sizes do not match -> flatten list + elif len(data) != element.value_size(): + flattened = [i for i in _flatten_list(data)] + assert len(flattened) == element.value_size() + return flattened + else: + # Do not return lists for non-MixedElement + if not isinstance(data, (tuple, list)): + return (data,) + else: + assert len(data) == 1 + return data + + def name_inifile(): # TODO pass some other option here. return "argv[1]" @@ -183,945 +207,6 @@ def name_initree(): return "initree" -@preamble -def define_dimension(name): - return "static const int {} = {};".format(name, get_dimension()) - - -def name_dimension(): - define_dimension("dim") - return "dim" - - -@preamble -def typedef_grid(name): - dim = name_dimension() - if any(_driver_data['form'].ufl_cell().cellname() in x for x in ["vertex", "interval", "quadrilateral", "hexahedron"]): - # For Yasp Grids the jacobi of the transformation is diagonal and constant on each cell - from dune.perftool.options import set_option - set_option('diagonal_transformation_matrix', True) - set_option('constant_transformation_matrix', True) - - range_type = type_range() - gridt = "Dune::YaspGrid<{}, Dune::EquidistantCoordinates<{},dim>>".format(dim, range_type) - include_file("dune/grid/yaspgrid.hh", filetag="driver") - else: - if any(_driver_data['form'].ufl_cell().cellname() in x for x in ["triangle", "tetrahedron"]): - # gridt = "Dune::UGGrid<{}>".format(dim) - # include_file("dune/grid/uggrid.hh", filetag="driver") - gridt = "Dune::ALUGrid<{}, {}, Dune::simplex, Dune::conforming>".format(dim, dim) - include_file("dune/alugrid/grid.hh", filetag="driver") - else: - raise PerftoolCodegenError("Cant match your geometry with a DUNE grid. Please report bug.") - return "using {} = {};".format(name, gridt) - - -def type_grid(): - typedef_grid("Grid") - return "Grid" - - -@preamble -def define_grid(name): - include_file("dune/testtools/gridconstruction.hh", filetag="driver") - ini = name_initree() - _type = type_grid() - return ["IniGridFactory<{}> factory({});".format(_type, ini), - "std::shared_ptr<{}> grid = factory.getGrid();".format(_type)] - - -def name_grid(): - define_grid("grid") - return "grid" - - -@preamble -def typedef_leafview(name): - grid = type_grid() - return "using {} = {}::LeafGridView;".format(name, grid) - - -def type_leafview(): - typedef_leafview("GV") - return "GV" - - -@preamble -def define_leafview(name): - _type = type_leafview() - grid = name_grid() - return "{} {} = {}->leafGridView();".format(_type, name, grid) - - -def name_leafview(): - define_leafview("gv") - return "gv" - - -@preamble -def typedef_vtkwriter(name): - include_file("dune/grid/io/file/vtk/subsamplingvtkwriter.hh", filetag="driver") - gv = type_leafview() - return "using {} = Dune::SubsamplingVTKWriter<{}>;".format(name, gv) - - -def type_vtkwriter(): - typedef_vtkwriter("VTKWriter") - return "VTKWriter" - - -@preamble -def define_subsamplinglevel(name): - ini = name_initree() - return "int {} = {}.get<int>(\"vtk.subsamplinglevel\", 0);".format(name, ini) - - -def name_subsamplinglevel(): - define_subsamplinglevel("sublevel") - return "sublevel" - - -@preamble -def define_vtkwriter(name): - _type = type_vtkwriter() - gv = name_leafview() - subsamp = name_subsamplinglevel() - return "{} {}({}, {});".format(_type, name, gv, subsamp) - - -def name_vtkwriter(): - define_vtkwriter("vtkwriter") - return "vtkwriter" - - -@preamble -def typedef_domainfield(name): - gridt = type_grid() - return "using {} = {}::ctype;".format(name, gridt) - - -def type_domainfield(): - typedef_domainfield("DF") - return "DF" - - -def basetype_range(): - if get_option('opcounter'): - from dune.perftool.pdelab.driver.timings import setup_timer - setup_timer() - return "oc::OpCounter<double>" - else: - return "double" - - -@preamble -def typedef_range(name): - return "using {} = {};".format(name, basetype_range()) - - -def type_range(): - typedef_range("RangeType") - return "RangeType" - - -@preamble -def typedef_fem(expr, name): - gv = type_leafview() - df = type_domainfield() - r = type_range() - dim = name_dimension() - if get_option("blockstructured"): - include_file("dune/perftool/blockstructured/blockstructuredqkfem.hh", filetag="driver") - return "using {} = Dune::PDELab::BlockstructuredQkLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, gv, df, r, expr._degree) - if isPk(expr): - include_file("dune/pdelab/finiteelementmap/pkfem.hh", filetag="driver") - return "using {} = Dune::PDELab::PkLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, gv, df, r, expr._degree) - if isQk(expr): - include_file("dune/pdelab/finiteelementmap/qkfem.hh", filetag="driver") - return "using {} = Dune::PDELab::QkLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, gv, df, r, expr._degree) - if isDG(expr): - if isQuadrilateral(expr): - include_file("dune/pdelab/finiteelementmap/qkdg.hh", filetag="driver") - # TODO allow switching the basis here! - return "using {} = Dune::PDELab::QkDGLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, df, r, expr._degree, dim) - if isSimplical(expr): - include_file("dune/pdelab/finiteelementmap/opbfem.hh", filetag="driver") - return "using {} = Dune::PDELab::OPBLocalFiniteElementMap<{}, {}, {}, {}, Dune::GeometryType::simplex>;".format(name, df, r, expr._degree, dim) - raise NotImplementedError("Geometry type not known in code generation") - - raise NotImplementedError("FEM not implemented in dune-perftool") - - -def type_fem(expr): - name = "{}_FEM".format(FEM_name_mangling(expr).upper()) - typedef_fem(expr, name) - return name - - -@preamble -def define_fem(expr, name): - femtype = type_fem(expr) - if isDG(expr): - return "{} {};".format(femtype, name) - else: - gv = name_leafview() - return "{} {}({});".format(femtype, name, gv) - - -def name_fem(expr): - name = "{}_fem".format(FEM_name_mangling(expr).lower()) - define_fem(expr, name) - return name - - -@preamble -def define_blocksize(name, expr): - assert isDG(expr) - assert isQuadrilateral(expr) - dimension = name_dimension() - degree = expr._degree - return "static const int {} = Dune::QkStuff::QkSize<{}, {}>::value;".format(name, degree, dimension) - - -def name_blocksize(expr): - name = "blocksize" - define_blocksize(name, expr) - return name - - -@preamble -def typedef_vectorbackend(name, expr): - include_file("dune/pdelab/backend/istl.hh", filetag="driver") - if get_option("fastdg"): - blocksize = name_blocksize(expr) - return "using {} = Dune::PDELab::istl::VectorBackend<Dune::PDELab::istl::Blocking::fixed, {}>;".format(name, blocksize) - else: - return "using {} = Dune::PDELab::istl::VectorBackend<Dune::PDELab::istl::Blocking::none, 1>;".format(name) - - -def type_vectorbackend(expr): - name = "VectorBackend" - typedef_vectorbackend(name, expr) - return name - - -def type_orderingtag(): - return "Dune::PDELab::LexicographicOrderingTag" - - -@preamble -def typedef_dirichlet_constraintsassembler(name): - include_file("dune/pdelab/constraints/conforming.hh", filetag="driver") - return "using {} = Dune::PDELab::ConformingDirichletConstraints;".format(name) - - -@preamble -def typedef_no_constraintsassembler(name): - return "using {} = Dune::PDELab::NoConstraints;".format(name) - - -def type_constraintsassembler(dirichlet): - if dirichlet[1]: - typedef_dirichlet_constraintsassembler("DirichletConstraintsAssember") - return "DirichletConstraintsAssember" - else: - typedef_no_constraintsassembler("NoConstraintsAssembler") - return "NoConstraintsAssembler" - - -@preamble -def typedef_constraintscontainer(element, name): - gfs = type_gfs(element) - r = type_range() - return "using {} = {}::ConstraintsContainer<{}>::Type;".format(name, gfs, r) - - -def type_constraintscontainer(element): - name = "{}_cc".format(FEM_name_mangling(element)).upper() - typedef_constraintscontainer(element, name) - return name - - -@preamble -def define_constraintscontainer(expr, name): - cctype = type_constraintscontainer(expr) - return ["{} {};".format(cctype, name), "{}.clear();".format(name)] - - -# TODO this does not yet fully support having same elements with different constraints! -@fem_metadata_dependent_symbol -def name_constraintscontainer(expr): - name = "{}{}_cc".format(FEM_name_mangling(expr), "_dirichlet" if has_constraints(expr) else "").lower() - define_constraintscontainer(expr, name) - return name - - -@preamble -def define_intersection_lambda(expression, name): - from dune.perftool.ufl.execution import Expression - from ufl.classes import Expr - if expression is None: - return "auto {} = [&](const auto& x){{ return 0.0; }};".format(name) - elif isinstance(expression, Expression): - if expression.is_global: - return "auto {} = [&](const auto& x){{ {} }};".format(name, expression.c_expr[0]) - else: - return "auto {} = [&](const auto& is, const auto& x){{ {} }};".format(name, expression.c_expr[0]) - elif isinstance(expression, Expr): - # Set up a visitor - with global_context(integral_type="exterior_facet", formdata=_driver_data["formdata"], driver=True): - from dune.perftool.ufl.visitor import UFL2LoopyVisitor - from dune.perftool.pdelab import PDELabInterface - visitor = UFL2LoopyVisitor(PDELabInterface(), "exterior_facet", {}) - from pymbolic.mapper.c_code import CCodeMapper - ccm = CCodeMapper() - expr = visitor(expression) - return "auto {} = [&](const auto& x){{ return {}; }};".format(name, ccm(expr)) - - raise ValueError("Expression not understood") - - -def name_bctype_lambda(name, dirichlet): - name = name + "_lambda" - define_intersection_lambda(dirichlet, name) - return name - - -@preamble -def define_bctype_function(dirichlet, name): - gv = name_leafview() - bctype_lambda = name_bctype_lambda(name, dirichlet) - include_file('dune/pdelab/function/callableadapter.hh', filetag='driver') - return "auto {} = Dune::PDELab::makeBoundaryConditionFromCallable({}, {});".format(name, - gv, - bctype_lambda, - ) - - -@preamble -def define_powergfs_constraints(name, child, dim): - include_file('dune/pdelab/constraints/common/constraintsparameters.hh', filetag='driver') - return "Dune::PDELab::PowerConstraintsParameters<decltype({}), {}> {}({});".format(child, dim, name, child) - - -@preamble -def define_compositegfs_constraints(name, *children): - include_file('dune/pdelab/constraints/common/constraintsparameters.hh', filetag='driver') - return "Dune::PDELab::CompositeConstraintsParameters<{}> {}({});".format(', '.join('decltype({})'.format(c) for c in children), - name, - ', '.join(c for c in children) - ) - - -@cached -def name_bctype_function(expr): - from ufl import MixedElement, VectorElement, TensorElement - if isinstance(expr, (VectorElement, TensorElement)): - element, (dirichlet, _) = get_constraints_metadata(expr) - # get the correct name from the corresponding UFL file - from dune.perftool.generation import get_global_context_value - name = get_global_context_value("data").object_names.get(id(dirichlet), "everywhere") - define_bctype_function(dirichlet, name) - pgfs_name = '{}_{}'.format(name, expr.num_sub_elements()) - define_powergfs_constraints(pgfs_name, name, expr.num_sub_elements()) - return pgfs_name - if isinstance(expr, MixedElement): - children = tuple(name_bctype_function(el) for el in expr.sub_elements()) - name = '_'.join(children) - define_compositegfs_constraints(name, *children) - return name - - # So, this seems to be a leaf! - element, (dirichlet, _) = get_constraints_metadata(expr) - - # get the correct name from the corresponding UFL file - from dune.perftool.generation import get_global_context_value - name = get_global_context_value("data").object_names.get(id(dirichlet), "everywhere") - - define_bctype_function(dirichlet, name) - return name - - -@preamble -def assemble_constraints(name, expr): - bctype_function = name_bctype_function(expr) - gfs = name_gfs(expr) - return "Dune::PDELab::constraints({}, {}, {});".format(bctype_function, - gfs, - name, - ) - - -def name_assembled_constraints(expr): - name = name_constraintscontainer(expr) - if has_constraints(expr): - assemble_constraints(name, expr) - return name - - -@preamble -def typedef_gfs(element, dirichlet, name): - vb = type_vectorbackend(element) - from ufl import FiniteElement, MixedElement, VectorElement, EnrichedElement, RestrictedElement, TensorElement - if isinstance(element, FiniteElement): - gv = type_leafview() - fem = type_fem(element) - cass = type_constraintsassembler(dirichlet) - return "using {} = Dune::PDELab::GridFunctionSpace<{}, {}, {}, {}>;".format(name, gv, fem, cass, vb) - if isinstance(element, (VectorElement, TensorElement)): - include_file("dune/pdelab/gridfunctionspace/vectorgridfunctionspace.hh", filetag="driver") - gv = type_leafview() - fem = type_fem(element.sub_elements()[0]) - # TODO implement symmetry here - dim = element.num_sub_elements() - cass = type_constraintsassembler(dirichlet) - return "using {} = Dune::PDELab::VectorGridFunctionSpace<{}, {}, {}, {}, {}, {}>;".format(name, gv, fem, dim, vb, vb, cass) - if isinstance(element, MixedElement): - ot = type_orderingtag() - args = ", ".join(type_gfs(e) for e in element.sub_elements()) - return "using {} = Dune::PDELab::CompositeGridFunctionSpace<{}, {}, {}>;".format(name, vb, ot, args) - if isinstance(element, EnrichedElement): - raise NotImplementedError("Dune does not support enriched elements!") - if isinstance(element, RestrictedElement): - raise NotImplementedError("Dune does not support restricted elements!") - - -@fem_metadata_dependent_symbol -def type_gfs(expr): - element, dirichlet = get_constraints_metadata(expr) - name = "{}{}_gfs".format(FEM_name_mangling(element), "_dirichlet" if dirichlet else "").upper() - typedef_gfs(element, dirichlet, name) - return name - - -@preamble -def define_gfs(element, dirichlet, name): - gfstype = type_gfs(element) - from ufl import FiniteElement, MixedElement, VectorElement, EnrichedElement, RestrictedElement, TensorElement - if isinstance(element, FiniteElement): - gv = name_leafview() - fem = name_fem(element) - return "{} {}({}, {});".format(gfstype, name, gv, fem) - if isinstance(element, (VectorElement, TensorElement)): - gv = name_leafview() - fem = name_fem(element.sub_elements()[0]) - return "{} {}({}, {});".format(gfstype, name, gv, fem) - if isinstance(element, MixedElement): - args = ", ".join(name_gfs(childgfs) for childgfs in element.sub_elements()) - return "{} {}({});".format(gfstype, name, args) - raise NotImplementedError("Dune does not support this type of finite element!") - - -@fem_metadata_dependent_symbol -def name_gfs(expr): - element, dirichlet = get_constraints_metadata(expr) - name = "{}{}_gfs".format(FEM_name_mangling(element), "_dirichlet" if dirichlet else "").lower() - define_gfs(element, dirichlet, name) - return name - - -# TODO adjust for blockstructured -@preamble -def define_dofestimate(name): - # Provide a worstcase estimate for the number of entries per row based on the given gridfunction space and cell geometry - if isQuadrilateral(get_trial_element()): - geo_factor = "4" - else: - geo_factor = "6" - gfs = name_gfs(get_trial_element()) - ini = name_initree() - - # Assure that gfs in initialized - formdata = _driver_data['formdata'] - x = name_vector(formdata) - define_vector(x, formdata) - - return ["int generic_dof_estimate = {} * {}.maxLocalSize();".format(geo_factor, gfs), - "int {} = {}.get<int>(\"istl.number_of_nnz\", generic_dof_estimate);".format(name, ini)] - - -def name_dofestimate(): - define_dofestimate("dofestimate") - return "dofestimate" - - -@preamble -def typedef_matrixbackend(name): - include_file("dune/pdelab/backend/istl.hh", filetag="driver") - return "using {} = Dune::PDELab::istl::BCRSMatrixBackend<>;".format(name) - - -def type_matrixbackend(): - typedef_matrixbackend("MatrixBackend") - return "MatrixBackend" - - -@preamble -def define_matrixbackend(name): - mbtype = type_matrixbackend() - dof = name_dofestimate() - return "{} {}({});".format(mbtype, name, dof) - - -def name_matrixbackend(): - define_matrixbackend("mb") - return "mb" - - -def type_parameters(formdata): - from dune.perftool.generation import get_global_context_value - data = get_global_context_value("data") - from dune.perftool.pdelab.parameter import parameterclass_basename - name = parameterclass_basename(formdata, data) - return name - - -@preamble -def define_parameters(name, formdata): - partype = type_parameters(formdata) - return "{} {};".format(partype, name) - - -def name_parameters(formdata): - name = form_name_suffix("params", formdata) - define_parameters(name, formdata) - return name - - -@preamble -def typedef_localoperator(name, formdata): - # No Parameter class here, yet - # params = type_parameters() - # return "using {} = LocalOperator<{}>;".format(name, params) - ugfs = type_gfs(get_trial_element()) - vgfs = type_gfs(get_test_element()) - from dune.perftool.generation import get_global_context_value - data = get_global_context_value("data") - filename = get_option("operator_file") - include_file(filename, filetag="driver") - from dune.perftool.pdelab.localoperator import localoperator_basename - lopname = localoperator_basename(formdata, data) - range_type = type_range() - return "using {} = {}<{}, {}, {}>;".format(name, lopname, ugfs, vgfs, range_type) - - -def type_localoperator(formdata): - name = form_name_suffix("LOP", formdata).upper() - typedef_localoperator(name, formdata) - return name - - -@preamble -def define_localoperator(name, formdata): - loptype = type_localoperator(formdata) - ini = name_initree() - params = name_parameters(formdata) - return "{} {}({}, {});".format(loptype, name, ini, params) - - -def name_localoperator(formdata): - name = form_name_suffix("lop", formdata) - define_localoperator(name, formdata) - return name - - -@preamble -def typedef_gridoperator(name, formdata): - ugfs = type_gfs(get_trial_element()) - vgfs = type_gfs(get_test_element()) - lop = type_localoperator(formdata) - ucc = type_constraintscontainer(get_trial_element()) - vcc = type_constraintscontainer(get_test_element()) - mb = type_matrixbackend() - df = type_domainfield() - r = type_range() - if get_option("fastdg"): - if not get_option("sumfact"): - raise PerftoolCodegenError("FastDGGridOperator is only implemented for sumfactorization.") - include_file("dune/pdelab/gridoperator/fastdg.hh", filetag="driver") - return "using {} = Dune::PDELab::FastDGGridOperator<{}, {}, {}, {}, {}, {}, {}, {}, {}>;".format(name, ugfs, vgfs, lop, mb, df, r, r, ucc, vcc) - else: - include_file("dune/pdelab/gridoperator/gridoperator.hh", filetag="driver") - return "using {} = Dune::PDELab::GridOperator<{}, {}, {}, {}, {}, {}, {}, {}, {}>;".format(name, ugfs, vgfs, lop, mb, df, r, r, ucc, vcc) - - -def type_gridoperator(formdata): - name = form_name_suffix("GO", formdata).upper() - typedef_gridoperator(name, formdata) - return name - - -@preamble -def define_gridoperator(name, formdata): - gotype = type_gridoperator(formdata) - # TODO use formdata insteat of _driver_data object - ugfs = name_gfs(get_trial_element()) - ucc = name_assembled_constraints(get_trial_element()) - vgfs = name_gfs(get_test_element()) - vcc = name_assembled_constraints(get_test_element()) - lop = name_localoperator(formdata) - mb = name_matrixbackend() - return ["{} {}({}, {}, {}, {}, {}, {});".format(gotype, name, ugfs, ucc, vgfs, vcc, lop, mb), - "std::cout << \"gfs with \" << {}.size() << \" dofs generated \"<< std::endl;".format(ugfs), - "std::cout << \"cc with \" << {}.size() << \" dofs generated \"<< std::endl;".format(ucc)] - - -def name_gridoperator(formdata): - name = form_name_suffix("go", formdata) - define_gridoperator(name, formdata) - return name - - -@preamble -def typedef_vector(name, formdata): - go_type = type_gridoperator(formdata) - return "using {} = {}::Traits::Domain;".format(name, go_type) - - -def type_vector(formdata): - name = form_name_suffix("V", formdata).upper() - typedef_vector(name, formdata) - return name - - -@preamble -def define_vector(name, formdata): - vtype = type_vector(formdata) - gfs = name_gfs(get_trial_element()) - return ["{} {}({});".format(vtype, name, gfs), "{} = 0.0;".format(name)] - - -@preamble -def define_boundary_lambda(boundary, name): - from dune.perftool.ufl.execution import Expression - from ufl.classes import Expr - if boundary is None: - return "auto {} = [&](const auto& x){{ return 0.0; }};".format(name) - elif isinstance(boundary, Expression): - if boundary.is_global: - return "auto {} = [&](const auto& x){{ {} }};".format(name, boundary.c_expr[0]) - else: - return "auto {} = [&](const auto& e, const auto& x){{ {} }};".format(name, boundary.c_expr[0]) - elif isinstance(boundary, Expr): - # Set up a visitor - with global_context(integral_type="exterior_facet", formdata=_driver_data["formdata"], driver=True): - from dune.perftool.ufl.visitor import UFL2LoopyVisitor - from dune.perftool.pdelab import PDELabInterface - visitor = UFL2LoopyVisitor(PDELabInterface(), "exterior_facet", {}) - from dune.perftool.loopy.target import numpy_to_cpp_dtype - return "auto {} = [&](const auto& x){{ return ({}){}; }};".format(name, - numpy_to_cpp_dtype("float64"), - visitor(boundary)) - - raise ValueError("Expression not understood") - - -def name_boundary_lambda(boundary, name): - define_boundary_lambda(boundary, name + "lambda") - return name + "lambda" - - -@preamble -def define_boundary_function(boundary, name): - gv = name_leafview() - lambdaname = name_boundary_lambda(boundary, name) - include_file('dune/pdelab/function/callableadapter.hh', filetag='driver') - if is_stationary(): - return "auto {} = Dune::PDELab::makeGridFunctionFromCallable({}, {});".format(name, - gv, - lambdaname, - ) - else: - params = name_parameters(_driver_data['formdata']) - return "auto {} = Dune::PDELab::makeInstationaryGridFunctionFromCallable({}, {}, {});".format(name, - gv, - lambdaname, - params) - - -@preamble -def define_compositegfs_parameterfunction(name, *children): - return "Dune::PDELab::CompositeGridFunction<{}> {}({});".format(', '.join('decltype({})'.format(c) for c in children), - name, - ', '.join(children)) - - -def expression_splitter(expr, length): - if expr is None: - return (None,) * length - else: - from dune.perftool.ufl.execution import Expression, split_expression - from ufl.classes import ListTensor - if isinstance(expr, Expression): - return split_expression(expr) - elif isinstance(expr, ListTensor): - return expr.ufl_operands - - raise TypeError("No idea how to split {} in components".format(type(expr))) - - -@cached -def _name_boundary_function(element, boundary, name=None): - from ufl import MixedElement, VectorElement, TensorElement - if isinstance(element, (VectorElement, TensorElement)): - from dune.perftool.generation import get_global_context_value - basename = get_global_context_value("data").object_names.get(id(boundary), "veczero") - children = tuple(_name_boundary_function(el, exp, basename + '_' + str(i)) for el, exp, i in zip(element.sub_elements(), expression_splitter(boundary, element.num_sub_elements()), range(element.num_sub_elements()))) - define_compositegfs_parameterfunction(basename, *children) - return basename - if isinstance(element, MixedElement): - children = tuple(name_boundary_function(el) for el in element.sub_elements()) - name = '_'.join(children) - define_compositegfs_parameterfunction(name, *children) - return name - - from dune.perftool.generation import get_global_context_value - if name is None: - name = get_global_context_value("data").object_names.get(id(boundary), "zero") - - 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) - - return _name_boundary_function(element, boundary) - - -@preamble -def interpolate_vector(name, formdata): - define_vector(name, formdata) - element = get_trial_element() - bf = name_boundary_function(element) - gfs = name_gfs(element) - return "Dune::PDELab::interpolate({}, {}, {});".format(bf, - gfs, - name, - ) - - -def maybe_interpolate_vector(name, formdata): - element = get_trial_element() - if has_constraints(element): - interpolate_vector(name, formdata) - else: - define_vector(name, formdata) - - -def name_vector(formdata): - name = form_name_suffix("x", formdata) - maybe_interpolate_vector(name, formdata) - return name - - -@preamble -def typedef_linearsolver(name): - include_file("dune/pdelab/backend/istl.hh", filetag="driver") - return "using {} = Dune::PDELab::ISTLBackend_SEQ_UMFPack;".format(name) - - -def type_linearsolver(): - typedef_linearsolver("LinearSolver") - return "LinearSolver" - - -@preamble -def define_linearsolver(name): - lstype = type_linearsolver() - return "{} {}(false);".format(lstype, name) - - -def name_linearsolver(): - define_linearsolver("ls") - return "ls" - - -@preamble -def define_reduction(name): - ini = name_initree() - return "double {} = {}.get<double>(\"reduction\", 1e-12);".format(name, ini) - - -def name_reduction(): - define_reduction("reduction") - return "reduction" - - -@preamble -def typedef_stationarylinearproblemsolver(name): - include_file("dune/pdelab/stationary/linearproblem.hh", filetag="driver") - gotype = type_gridoperator(_driver_data['formdata']) - lstype = type_linearsolver() - xtype = type_vector(_driver_data['formdata']) - return "using {} = Dune::PDELab::StationaryLinearProblemSolver<{}, {}, {}>;".format(name, gotype, lstype, xtype) - - -def type_stationarylinearproblemsolver(): - typedef_stationarylinearproblemsolver("SLP") - return "SLP" - - -@preamble -def define_stationarylinearproblemsolver(name): - slptype = type_stationarylinearproblemsolver() - formdata = _driver_data['formdata'] - go = name_gridoperator(formdata) - ls = name_linearsolver() - x = name_vector(formdata) - red = name_reduction() - return "{} {}({}, {}, {}, {});".format(slptype, name, go, ls, x, red) - - -def name_stationarylinearproblemsolver(): - define_stationarylinearproblemsolver("slp") - return "slp" - - -@preamble -def typedef_stationarynonlinearproblemsolver(name, go_type): - include_file("dune/pdelab/newton/newton.hh", filetag="driver") - ls_type = type_linearsolver() - x_type = type_vector(_driver_data['formdata']) - return "using {} = Dune::PDELab::Newton<{}, {}, {}>;".format(name, go_type, ls_type, x_type) - - -def type_stationarynonlinearproblemssolver(go_type): - typedef_stationarynonlinearproblemsolver("SNP", go_type) - return "SNP" - - -@preamble -def define_stationarynonlinearproblemsolver(name, go_type, go): - snptype = type_stationarynonlinearproblemssolver(go_type) - x = name_vector(_driver_data['formdata']) - ls = name_linearsolver() - return "{} {}({}, {}, {});".format(snptype, name, go, x, ls) - - -def name_stationarynonlinearproblemsolver(go_type, go): - define_stationarynonlinearproblemsolver("snp", go_type, go) - return "snp" - - -@preamble -def typedef_timesteppingmethod(name): - r_type = type_range() - explicit = get_option('explicit_time_stepping') - if explicit: - return "using {} = Dune::PDELab::ExplicitEulerParameter<{}>;".format(name, r_type) - else: - return "using {} = Dune::PDELab::OneStepThetaParameter<{}>;".format(name, r_type) - - -def type_timesteppingmethod(): - typedef_timesteppingmethod("TSM") - return "TSM" - - -@preamble -def define_timesteppingmethod(name): - tsm_type = type_timesteppingmethod() - explicit = get_option('explicit_time_stepping') - if explicit: - return "{} {};".format(tsm_type, name) - else: - return "{} {}(1.0);".format(tsm_type, name) - - -def name_timesteppingmethod(): - define_timesteppingmethod("tsm") - return "tsm" - - -@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']) - explicit = get_option('explicit_time_stepping') - if explicit: - return "using {} = Dune::PDELab::OneStepGridOperator<{},{},false>;".format(name, go_type, mass_go_type) - else: - return "using {} = Dune::PDELab::OneStepGridOperator<{},{}>;".format(name, go_type, mass_go_type) - - -def type_instationarygridoperator(): - typedef_instationarygridoperator("IGO") - return "IGO" - - -@preamble -def define_instationarygridoperator(name): - igo_type = type_instationarygridoperator() - go = name_gridoperator(_driver_data['formdata']) - mass_go = name_gridoperator(_driver_data['mass_formdata']) - return "{} {}({}, {});".format(igo_type, name, go, mass_go) - - -def name_instationarygridoperator(): - define_instationarygridoperator("igo") - return "igo" - - -@preamble -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']) - return "using {} = Dune::PDELab::OneStepMethod<{}, {}, {}, {}, {}>;".format(name, r_type, igo_type, snp_type, vector_type, vector_type) - - -def type_onestepmethod(): - typedef_onestepmethod("OSM") - return "OSM" - - -@preamble -def define_onestepmethod(name): - ilptype = type_onestepmethod() - tsm = name_timesteppingmethod() - igo_type = type_instationarygridoperator() - igo = name_instationarygridoperator() - snp = name_stationarynonlinearproblemsolver(igo_type, igo) - return "{} {}({},{},{});".format(ilptype, name, tsm, igo, snp) - - -def name_onestepmethod(): - define_onestepmethod("osm") - return "osm" - - -@preamble -def typedef_explicitonestepmethod(name): - r_type = type_range() - igo_type = type_instationarygridoperator() - ls_type = type_linearsolver() - vector_type = type_vector(_driver_data['formdata']) - return "using {} = Dune::PDELab::ExplicitOneStepMethod<{}, {}, {}, {}>;".format(name, r_type, igo_type, ls_type, vector_type) - - -def type_explicitonestepmethod(): - typedef_explicitonestepmethod("EOSM") - return "EOSM" - - -@preamble -def define_explicitonestepmethod(name): - eosm_type = type_explicitonestepmethod() - tsm = name_timesteppingmethod() - igo = name_instationarygridoperator() - ls = name_linearsolver() - return "{} {}({}, {}, {});".format(eosm_type, name, tsm, igo, ls) - - -def name_explicitonestepmethod(): - define_explicitonestepmethod("eosm") - return "eosm" - - @preamble def define_mpihelper(name): include_file("dune/common/parallel/mpihelper.hh", filetag="driver") @@ -1134,306 +219,6 @@ def name_mpihelper(): return name -@preamble -def dune_solve(): - # Test if form is linear in ansatzfunction - linear = is_linear(_driver_data['formdata'].original_form) - - # Test wether we want to do matrix free operator evaluation - matrix_free = get_option('matrix_free') - - # Get right solve command - if linear and matrix_free: - formdata = _driver_data['formdata'] - go = name_gridoperator(formdata) - x = name_vector(formdata) - include_file("dune/perftool/matrixfree.hh", filetag="driver") - solve = "solveMatrixFree({},{});".format(go, x) - elif linear and not matrix_free: - slp = name_stationarylinearproblemsolver() - solve = "{}.apply();".format(slp) - elif not linear and matrix_free: - # TODO copy of linear case and obviously broken, used to generate something ;) - formdata = _driver_data['formdata'] - go = name_gridoperator(formdata) - x = name_vector(formdata) - include_file("dune/perftool/matrixfree.hh", filetag="driver") - solve = "solveNonlinearMatrixFree({},{});".format(go, x) - elif not linear and not matrix_free: - go_type = type_gridoperator(_driver_data['formdata']) - go = name_gridoperator(_driver_data['formdata']) - snp = name_stationarynonlinearproblemsolver(go_type, go) - solve = "{}.apply();".format(snp) - - if get_option('instrumentation_level') >= 2: - from dune.perftool.pdelab.driver.timings import setup_timer, name_timing_stream - setup_timer() - from dune.perftool.generation import post_include - post_include("HP_DECLARE_TIMER(solve);", filetag="driver") - - # Print times after solving - from dune.perftool.generation import get_global_context_value - formdatas = get_global_context_value("formdatas") - print_times = [] - for formdata in formdatas: - lop_name = name_localoperator(formdata) - timestream = name_timing_stream() - print_times.append("{}.dump_timers({}, {}, true);".format(lop_name, timestream, name_timing_identifier())) - - solve = ["HP_TIMER_START(solve);", - "{}".format(solve), - "HP_TIMER_STOP(solve);", - "DUMP_TIMER(solve, {}, true);".format(timestream), - ] - if get_option('instrumentation_level') >= 3: - solve.extend(print_times) - - return solve - - -@preamble -def define_vtkfile(name): - ini = name_initree() - include_file("string", filetag="driver") - return "std::string {} = {}.get<std::string>(\"wrapper.vtkcompare.name\", \"output\");".format(name, ini) - - -def name_vtkfile(): - define_vtkfile("vtkfile") - return "vtkfile" - - -@preamble -def print_residual(): - ini = name_initree() - formdata = _driver_data['formdata'] - n_go = name_gridoperator(formdata) - v = name_vector(formdata) - t_v = type_vector(formdata) - include_file("random", system=True, filetag="driver") - - return ["if ({}.get<bool>(\"printresidual\", false)) {{".format(ini), - " using Dune::PDELab::Backend::native;", - " {} r({});".format(t_v, v), - " // Setup random input", - " std::size_t seed = 0;", - " auto rng = std::mt19937_64(seed);", - " auto dist = std::uniform_real_distribution<>(-1., 1.);", - " for (auto& v : {})".format(v), - " v = dist(rng);", - " r=0.0;", - " {}.residual({}, r);".format(n_go, v), - " Dune::printvector(std::cout, native(r), \"residual vector\", \"row\");", - "}"] - - -@preamble -def print_matrix(): - formdata = _driver_data['formdata'] - ini = name_initree() - t_go = type_gridoperator(formdata) - n_go = name_gridoperator(formdata) - v = name_vector(formdata) - t_v = type_vector(formdata) - - return ["if ({}.get<bool>(\"printmatrix\", false)) {{".format(ini), - " using M = typename {}::Traits::Jacobian;".format(t_go), - " M m({});".format(n_go), - " {}.jacobian({},m);".format(n_go, v), - " using Dune::PDELab::Backend::native;", - " Dune::printmatrix(std::cout, native(m),\"global stiffness matrix\",\"row\",9,1);", - "}"] - - -@preamble -def define_gfs_name(element, prefix=()): - from ufl import MixedElement, VectorElement, TensorElement - if isinstance(element, (VectorElement, TensorElement)): - gfs = name_gfs(element) - return "{}.name(\"data_{}\");".format(gfs, "_".join(str(p) for p in prefix)) - if isinstance(element, MixedElement): - for (i, el) in enumerate(element.sub_elements()): - define_gfs_name(el, prefix + (i,)) - return "" - # This is a scalar leaf - gfs = name_gfs(element) - return "{}.name(\"data_{}\");".format(gfs, "_".join(str(p) for p in prefix)) - - -def type_predicate(): - include_file("dune/perftool/vtkpredicate.hh", filetag="driver") - return "CuttingPredicate" - - -@preamble -def define_predicate(name): - t = type_predicate() - return "{} {};".format(t, name) - - -def name_predicate(): - define_predicate("predicate") - return "predicate" - - -@preamble -def vtkoutput(): - element = get_trial_element() - define_gfs_name(element) - include_file("dune/pdelab/gridfunctionspace/vtk.hh", filetag="driver") - vtkwriter = name_vtkwriter() - gfs = name_gfs(element) - vec = name_vector(_driver_data['formdata']) - vtkfile = name_vtkfile() - predicate = name_predicate() - dune_solve() - 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() - - return ["Dune::PDELab::addSolutionToVTKWriter({}, {}, {}, Dune::PDELab::vtk::defaultNameScheme(), {});".format(vtkwriter, gfs, vec, predicate), - "{}.write({}, Dune::VTK::ascii);".format(vtkwriter, vtkfile)] - - -@preamble -def define_time(name): - return "double {} = 0.0;".format(name) - - -def name_time(): - define_time("time") - return "time" - - -@preamble -def typedef_vtk_sequence_writer(name): - include_file("dune/grid/io/file/vtk/vtksequencewriter.hh", filetag="driver") - gv_type = type_leafview() - return "using {} = Dune::VTKSequenceWriter<{}>;".format(name, gv_type) - - -def type_vtk_sequence_writer(): - typedef_vtk_sequence_writer("VTKSW") - return "VTKSW" - - -@preamble -def define_vtk_sequence_writer(name): - vtksw_type = type_vtk_sequence_writer() - vtkw_type = type_vtkwriter() - vtkw = name_vtkwriter() - vtkfile = name_vtkfile() - return "{} {}(std::make_shared<{}>({}), {});".format(vtksw_type, name, vtkw_type, vtkw, vtkfile) - - -def name_vtk_sequence_writer(): - define_vtk_sequence_writer("vtkSequenceWriter") - return "vtkSequenceWriter" - - -@preamble -def visualize_initial_condition(): - include_file("dune/pdelab/gridfunctionspace/vtk.hh", filetag="driver") - vtkwriter = name_vtk_sequence_writer() - element = get_trial_element() - define_gfs_name(element) - gfs = name_gfs(element) - vector = name_vector(_driver_data['formdata']) - predicate = name_predicate() - 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 time_loop(): - ini = name_initree() - formdata = _driver_data['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) - vector_type = type_vector(formdata) - vector = name_vector(formdata) - - # Choose between explicit and implicit time stepping - explicit = get_option('explicit_time_stepping') - if explicit: - osm = name_explicitonestepmethod() - apply_call = "{}.apply(time, dt, {}, {}new);".format(osm, vector, vector) - else: - boundary = name_boundary_function(expr) - osm = name_onestepmethod() - apply_call = "{}.apply(time, dt, {}, {}, {}new);".format(osm, vector, boundary, vector) - - # Setup visualization - visualize_initial_condition() - vtk_sequence_writer = name_vtk_sequence_writer() - - return ["", - "double T = {}.get<double>(\"instat.T\", 1.0);".format(ini), - "double dt = {}.get<double>(\"instat.dt\", 0.1);".format(ini), - "while (time<T-1e-8){", - " // Assemble constraints for new time step", - " {}.setTime({}+dt);".format(params, time), - " Dune::PDELab::constraints({}, {}, {});".format(bctype, gfs, cc), - "", - " // Do time step", - " {} {}new({});".format(vector_type, vector, vector), - " {}".format(apply_call), - "", - " // Accept new time step", - " {} = {}new;".format(vector, vector), - " time += dt;", - "", - " // Output to VTK File", - " {}.write({}, Dune::VTK::appendedraw);".format(vtk_sequence_writer, time), - "}", - ""] - - -def solve_instationary(): - # Test if form is linear in ansatzfunction - linear = is_linear(_driver_data['formdata'].original_form) - - # Test wether we want to do matrix free operator evaluation - matrix_free = get_option('matrix_free') - - # Create time loop - if linear and matrix_free: - assert False - elif linear and not matrix_free: - time_loop() - if not linear and matrix_free: - assert False - elif not linear and not matrix_free: - assert False - - 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 -def return_statement(): - from dune.perftool.pdelab.driver.error import name_test_fail_variable - fail = name_test_fail_variable() - return "return {};".format(fail) - - def _blockstructured_degree_helper(element, op): element._degree = op(element._degree, get_option("number_of_blocks")) from ufl import MixedElement, VectorElement, TensorElement @@ -1474,9 +259,12 @@ def generate_driver(formdatas, data): evaluate_residual_timer() apply_jacobian_timer() elif is_stationary(): - # We could also use solve if we are not interested in visualization + from dune.perftool.pdelab.driver.solve import dune_solve + vec = dune_solve() + from dune.perftool.pdelab.driver.vtk import vtkoutput vtkoutput() else: + from dune.perftool.pdelab.driver.instationary import solve_instationary solve_instationary() # Make sure that timestream is declared before retrieving chache items @@ -1485,6 +273,7 @@ def generate_driver(formdatas, data): setup_timer() timestream = name_timing_stream() + from dune.perftool.pdelab.driver.error import return_statement return_statement() from dune.perftool.generation import retrieve_cache_items diff --git a/python/dune/perftool/pdelab/driver/constraints.py b/python/dune/perftool/pdelab/driver/constraints.py new file mode 100644 index 00000000..a75016c2 --- /dev/null +++ b/python/dune/perftool/pdelab/driver/constraints.py @@ -0,0 +1,144 @@ +from dune.perftool.generation import (include_file, + preamble, + ) +from dune.perftool.pdelab.driver import (FEM_name_mangling, + get_formdata, + get_trial_element, + ) +from dune.perftool.pdelab.driver.gridfunctionspace import (name_leafview, + name_trial_gfs, + type_range, + type_trial_gfs, + preprocess_leaf_data, + ) + +from ufl import FiniteElement, MixedElement, TensorElement, VectorElement + + +def name_assembled_constraints(): + name = name_constraintscontainer() + define_constraintscontainer(name) + assemble_constraints(name) + return name + + +@preamble +def assemble_constraints(name): + element = get_trial_element() + gfs = name_trial_gfs() + is_dirichlet = preprocess_leaf_data(element, "is_dirichlet") + bctype_function = name_bctype_function(element, is_dirichlet) + return "Dune::PDELab::constraints({}, {}, {});".format(bctype_function, + gfs, + name, + ) + + +def name_bctype_function(element, is_dirichlet): + if isinstance(element, (VectorElement, TensorElement)): + subel = element.sub_element()[0] + subgfs = name_bctype_function(subel, is_dirichlet[:subel.value_size()]) + name = "{}_pow{}bctype".format(subgfs, element.num_sub_elements()) + define_power_bctype_function(element, 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()])) + k = k + subel.value_size() + name = "_".join(subgfs) + define_composite_bctype_function(element, is_dirichlet, name, subgfs) + return name + else: + assert isinstance(element, FiniteElement) + name = "{}_bctype".format(FEM_name_mangling(element).lower()) + define_bctype_function(element, is_dirichlet[0], name) + return name + + +@preamble +def define_bctype_function(element, is_dirichlet, name): + gv = name_leafview() + bctype_lambda = name_bctype_lambda(name, is_dirichlet) + include_file('dune/pdelab/function/callableadapter.hh', filetag='driver') + return "auto {} = Dune::PDELab::makeBoundaryConditionFromCallable({}, {});".format(name, + gv, + bctype_lambda, + ) + + +@preamble +def define_power_bctype_function(element, name, subgfs): + include_file('dune/pdelab/constraints/common/constraintsparameters.hh', filetag='driver') + return "Dune::PDELab::PowerConstraintsParameters<decltype({}), {}> {}({});".format(subgfs, element.num_sub_elements(), name, subgfs) + + +@preamble +def define_composite_bctype_function(element, is_dirichlet, name, subgfs): + include_file('dune/pdelab/constraints/common/constraintsparameters.hh', filetag='driver') + return "Dune::PDELab::CompositeConstraintsParameters<{}> {}({});".format(', '.join('decltype({})'.format(c) for c in subgfs), + name, + ', '.join(c for c in subgfs) + ) + + +def name_bctype_lambda(name, func): + name = name + "_lambda" + define_intersection_lambda(name, func) + return name + + +@preamble +def define_intersection_lambda(name, func): + from dune.perftool.ufl.execution import Expression + from ufl.classes import Expr + if func is None: + func = 0. + if isinstance(func, (int, float)): + return "auto {} = [&](const auto& x){{ return {}; }};".format(name, float(func)) + elif isinstance(func, Expression): + if expression.is_global: + return "auto {} = [&](const auto& x){{ {} }};".format(name, func.c_expr[0]) + else: + return "auto {} = [&](const auto& is, const auto& x){{ {} }};".format(name, func.c_expr[0]) + elif isinstance(func, Expr): + # Set up a visitor + with global_context(integral_type="exterior_facet", formdata=get_formdata(), driver=True): + from dune.perftool.ufl.visitor import UFL2LoopyVisitor + from dune.perftool.pdelab import PDELabInterface + visitor = UFL2LoopyVisitor(PDELabInterface(), "exterior_facet", {}) + from pymbolic.mapper.c_code import CCodeMapper + ccm = CCodeMapper() + expr = visitor(func) + return "auto {} = [&](const auto& x){{ return {}; }};".format(name, ccm(expr)) + + raise ValueError("Expression not understood") + + +@preamble +def typedef_constraintscontainer(name): + gfs = type_trial_gfs() + r = type_range() + return "using {} = {}::ConstraintsContainer<{}>::Type;".format(name, gfs, r) + + +def type_constraintscontainer(): + name = "{}_CC".format(type_trial_gfs()) + typedef_constraintscontainer(name) + return name + + +@preamble +def define_constraintscontainer(name): + cctype = type_constraintscontainer() + return ["{} {};".format(cctype, name), "{}.clear();".format(name)] + + +def name_constraintscontainer(): + gfs = name_trial_gfs() + name = "{}_cc".format(gfs) + element = get_trial_element() + is_dirichlet = preprocess_leaf_data(element, "is_dirichlet") + define_constraintscontainer(name) + return name diff --git a/python/dune/perftool/pdelab/driver/error.py b/python/dune/perftool/pdelab/driver/error.py index c02147a9..dbbb0b9c 100644 --- a/python/dune/perftool/pdelab/driver/error.py +++ b/python/dune/perftool/pdelab/driver/error.py @@ -5,6 +5,17 @@ from dune.perftool.generation import (cached, preamble, ) from dune.perftool.options import get_option +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.interpolate import (interpolate_vector, + name_boundary_function, + ) +from dune.perftool.pdelab.driver.solve import (define_vector, + name_vector, + ) @preamble @@ -18,37 +29,26 @@ def name_test_fail_variable(): return name -def name_vector_from_solution_expression(): - interpolate_solution_expression("solution") - return "solution" +def name_exact_solution(): + name = "solution" + define_vector(name, get_formdata()) + interpolate_exact_solution(name) + return name -@preamble -def interpolate_solution_expression(name): - from dune.perftool.pdelab.driver import (define_vector, - get_formdata, - get_trial_element, - name_gfs, - ) - formdata = get_formdata() - define_vector(name, formdata) +def interpolate_exact_solution(name): element = get_trial_element() - sol = name_solution_function() - gfs = name_gfs(element) - return "Dune::PDELab::interpolate({}, {}, {});".format(sol, - gfs, - name, - ) + 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(): - from dune.perftool.pdelab.driver import (get_formdata, - name_vector, - ) - v = name_vector(get_formdata()) - solution = name_vector_from_solution_expression() + solution = name_exact_solution() fail = name_test_fail_variable() return ["", @@ -64,7 +64,6 @@ def compare_dofs(): " {} = true;".format(fail)] - def type_discrete_grid_function(gfs): return "DGF_{}".format(gfs.upper()) @@ -77,149 +76,54 @@ def define_discrete_grid_function(gfs, vector_name, dgf_name): def name_discrete_grid_function(gfs, vector_name): - dgf_name = gfs + "_dgf" + dgf_name = "{}_dgf".format(gfs) define_discrete_grid_function(gfs, vector_name, dgf_name) return dgf_name -def type_subgfs(element, tree_path): - from dune.perftool.pdelab.driver import type_gfs - 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 define_subgfs(name, element, tree_path): - t = type_subgfs(element, tree_path) - - from dune.perftool.pdelab.driver import name_gfs - gfs = name_gfs(element) - - return '{} {}({});'.format(t, name, gfs) - - -def name_subgfs(element, tree_path): - from dune.perftool.pdelab.driver import name_gfs - 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 - - -@cached -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 Expression, split_expression - from ufl.classes import ListTensor - for i in tree_path: - if isinstance(expr, Expression): - expr = split_expression(expr)[int(i)] - elif isinstance(expr, tuple): - expr = expr[int(i)] - elif isinstance(expr, ListTensor): - expr = expr.ufl_operands[int(i)] - else: - raise TypeError("No idea how to split {}".format(type(expr))) - - from dune.perftool.generation import get_global_context_value - try: - name = get_global_context_value("data").object_names[id(expr)] - except KeyError: - from dune.perftool.generation import get_counter - name = 'generic_{}'.format(get_counter('__generic')) - - from dune.perftool.pdelab.driver import define_boundary_function - define_boundary_function(expr, name) - - return name - - -@preamble -def typedef_difference_squared_adapter(name, tree_path): - from dune.perftool.pdelab.driver import (get_formdata, - get_trial_element, - name_vector, - ) - element = get_trial_element() - formdata = get_formdata() - - solution_function = name_solution_function(tree_path) - gfs = name_subgfs(element, tree_path) - vector = name_vector(formdata) +def typedef_difference_squared_adapter(name): + sol = name_exact_solution() + vector = name_vector(get_formdata()) dgf = name_discrete_grid_function(gfs, vector) - return 'using {} = Dune::PDELab::DifferenceSquaredAdapter<decltype({}), decltype({})>;'.format(name, solution_function, dgf) + return 'using {} = Dune::PDELab::DifferenceSquaredAdapter<decltype({}), decltype({})>;'.format(name, sol, dgf) -def type_difference_squared_adapter(tree_path): - t = 'DifferenceSquared_{}'.format('_'.join(tree_path)) - typedef_difference_squared_adapter(t, tree_path) - return t +def type_difference_squared_adapter(): + name = 'DifferenceSquaredAdapter' + typedef_difference_squared_adapter(name) + return name @preamble -def define_difference_squared_adapter(name, tree_path): - from dune.perftool.pdelab.driver import (get_formdata, - get_trial_element, - name_vector, - ) - element = get_trial_element() - formdata = get_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) +def define_difference_squared_adapter(name): + t = type_difference_squared_adapter() + sol = name_exact_solution() + vector = name_vector(get_formdata()) dgf = name_discrete_grid_function(gfs, vector) - return '{} {}({}, {});'.format(t, name, solution_function, dgf) + return '{} {}({}, {});'.format(t, name, sol, dgf) -def name_difference_squared_adapter(tree_path): - name = 'differencesquared_{}'.format('_'.join(tree_path)) - define_difference_squared_adapter(name, tree_path) +def name_difference_squared_adapter(): + name = 'differencesquared_adapter' + define_difference_squared_adapter(name) return name @preamble -def _accumulate_L2_squared(tree_path): - dsa = name_difference_squared_adapter(tree_path) - t_dsa = type_difference_squared_adapter(tree_path) +def accumulate_L2_squared(): + dsa = name_difference_squared_adapter() 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", - " // 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=()): - from dune.perftool.pdelab.driver import get_trial_element - element = get_trial_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) + return ["// L2 error squared of difference between numerical", + "// solution and the interpolation of exact solution", + " Dune::PDELab::integrateGridFunction({}, {}, 10);".format(dsa, accum_error), + ] @preamble @@ -242,3 +146,10 @@ def compare_L2_squared(): 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")), " {} = true;".format(fail)] + + +@preamble +def return_statement(): + from dune.perftool.pdelab.driver.error import name_test_fail_variable + fail = name_test_fail_variable() + return "return {};".format(fail) diff --git a/python/dune/perftool/pdelab/driver/gridfunctionspace.py b/python/dune/perftool/pdelab/driver/gridfunctionspace.py new file mode 100644 index 00000000..b439ded1 --- /dev/null +++ b/python/dune/perftool/pdelab/driver/gridfunctionspace.py @@ -0,0 +1,345 @@ +from dune.perftool.generation import (include_file, + preamble, + ) +from dune.perftool.options import get_option, set_option +from dune.perftool.pdelab.driver import (FEM_name_mangling, + get_cell, + get_dimension, + get_test_element, + get_trial_element, + isDG, + isPk, + isQk, + isQuadrilateral, + isSimplical, + name_initree, + preprocess_leaf_data, + ) + +from ufl import FiniteElement, MixedElement, TensorElement, VectorElement + + +@preamble +def typedef_domainfield(name): + gridt = type_grid() + return "using {} = {}::ctype;".format(name, gridt) + + +def type_domainfield(): + typedef_domainfield("DF") + return "DF" + + +@preamble +def typedef_range(name): + if get_option('opcounter'): + from dune.perftool.pdelab.driver.timings import setup_timer + setup_timer() + return "using {} = oc::OpCounter<double>;".format(name) + else: + return "using {} = double;".format(name) + + +def type_range(): + name = "RangeType" + typedef_range(name) + return name + + +@preamble +def typedef_grid(name): + dim = get_dimension() + if isQuadrilateral(get_trial_element().cell()): + # For Yasp Grids the jacobi of the transformation is diagonal and constant on each cell + set_option('diagonal_transformation_matrix', True) + set_option('constant_transformation_matrix', True) + + range_type = type_range() + gridt = "Dune::YaspGrid<{0}, Dune::EquidistantCoordinates<{1}, {0}>>".format(dim, range_type) + include_file("dune/grid/yaspgrid.hh", filetag="driver") + else: + if isSimplical(get_trial_element().cell()): + # gridt = "Dune::UGGrid<{}>".format(dim) + # include_file("dune/grid/uggrid.hh", filetag="driver") + gridt = "Dune::ALUGrid<{}, {}, Dune::simplex, Dune::conforming>".format(dim, dim) + include_file("dune/alugrid/grid.hh", filetag="driver") + else: + raise PerftoolCodegenError("Cant match your geometry with a DUNE grid. Please report bug.") + return "using {} = {};".format(name, gridt) + + +def type_grid(): + name = "Grid" + typedef_grid(name) + return name + + +@preamble +def define_grid(name): + include_file("dune/testtools/gridconstruction.hh", filetag="driver") + ini = name_initree() + _type = type_grid() + return ["IniGridFactory<{}> factory({});".format(_type, ini), + "std::shared_ptr<{}> grid = factory.getGrid();".format(_type)] + + +def name_grid(): + name = "grid" + define_grid(name) + return name + + +@preamble +def typedef_leafview(name): + grid = type_grid() + return "using {} = {}::LeafGridView;".format(name, grid) + + +def type_leafview(): + name = "GV" + typedef_leafview(name) + return name + + +@preamble +def define_leafview(name): + _type = type_leafview() + grid = name_grid() + return "{} {} = {}->leafGridView();".format(_type, name, grid) + + +def name_leafview(): + name = "gv" + define_leafview(name) + return name + + +@preamble +def typedef_fem(element, name): + gv = type_leafview() + df = type_domainfield() + r = type_range() + dim = get_dimension() + if isQk(element): + include_file("dune/pdelab/finiteelementmap/qkfem.hh", filetag="driver") + return "using {} = Dune::PDELab::QkLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, gv, df, r, element.degree()) + if isPk(element): + include_file("dune/pdelab/finiteelementmap/pkfem.hh", filetag="driver") + return "using {} = Dune::PDELab::PkLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, gv, df, r, element.degree()) + if isDG(element): + if isQuadrilateral(element.cell()): + include_file("dune/pdelab/finiteelementmap/qkdg.hh", filetag="driver") + # TODO allow switching the basis here! + return "using {} = Dune::PDELab::QkDGLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, df, r, element.degree(), dim) + if isSimplical(element.cell()): + include_file("dune/pdelab/finiteelementmap/opbfem.hh", filetag="driver") + return "using {} = Dune::PDELab::OPBLocalFiniteElementMap<{}, {}, {}, {}, Dune::GeometryType::simplex>;".format(name, df, r, element.degree(), dim) + raise NotImplementedError("Geometry type not known in code generation") + + raise NotImplementedError("FEM not implemented in dune-perftool") + + +def type_fem(element): + name = "{}_FEM".format(FEM_name_mangling(element).upper()) + typedef_fem(element, name) + return name + + +@preamble +def define_fem(element, name): + femtype = type_fem(element) + from dune.perftool.pdelab.driver import isDG + if isDG(element): + return "{} {};".format(femtype, name) + else: + gv = name_leafview() + return "{} {}({});".format(femtype, name, gv) + + +def name_fem(element): + assert isinstance(element, FiniteElement) + name = "{}_fem".format(FEM_name_mangling(element).lower()) + define_fem(element, name) + return name + + +def name_trial_gfs(): + element = get_trial_element() + is_dirichlet = preprocess_leaf_data(element, "is_dirichlet") + return name_gfs(element, is_dirichlet) + + +def name_test_gfs(): + element = get_test_element() + is_dirichlet = preprocess_leaf_data(element, "is_dirichlet") + return name_gfs(element, is_dirichlet) + + +def name_gfs(element, is_dirichlet): + 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()) + 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()])) + k = k + subel.value_size() + name = "_".join(subgfs) + define_composite_gfs(element, is_dirichlet, name, subgfs) + return name + else: + assert isinstance(element, FiniteElement) + name = "{}{}_gfs".format(FEM_name_mangling(element).lower(), + "_dirichlet" if is_dirichlet else "", + ) + define_gfs(element, is_dirichlet, name) + return name + + +def type_test_gfs(): + element = get_test_element() + is_dirichlet = preprocess_leaf_data(element, "is_dirichlet") + return type_gfs(element, is_dirichlet) + + +def type_trial_gfs(): + element = get_trial_element() + is_dirichlet = preprocess_leaf_data(element, "is_dirichlet") + return type_gfs(element, is_dirichlet) + + +def type_gfs(element, is_dirichlet): + if isinstance(element, (VectorElement, TensorElement)): + subel = element.sub_element()[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) + return name + if isinstance(element, MixedElement): + k = 0 + subgfs = [] + for subel in element.sub_elements(): + 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) + return name + else: + assert isinstance(element, FiniteElement) + name = "{}{}_GFS".format(FEM_name_mangling(element).upper(), + "_dirichlet" if is_dirichlet else "", + ) + typedef_gfs(element, is_dirichlet, name) + return name + + +@preamble +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) + + +@preamble +def define_power_gfs(element, is_dirichlet, name, subgfs): + gv = name_leafview() + fem = name_fem(element.sub_elements()[0]) + return "{} {}({}, {});".format(gfstype, name, gv, fem) + + +@preamble +def define_composite_gfs(element, is_dirichlet, name, subgfs): + gfstype = type_gfs(element, is_dirichlet) + return "{} {}({});".format(gfstype, name, ", ".join(subgfs)) + + +@preamble +def typedef_gfs(element, is_dirichlet, name): + vb = type_vectorbackend(element) + gv = type_leafview() + fem = type_fem(element) + cass = type_constraintsassembler(bool(is_dirichlet)) + return "using {} = Dune::PDELab::GridFunctionSpace<{}, {}, {}, {}>;".format(name, gv, fem, cass, vb) + + +@preamble +def typedef_power_gfs(element, is_dirichlet, name, subgfs): + include_file("dune/pdelab/gridfunctionspace/vectorgridfunctionspace.hh", filetag="driver") + gv = type_leafview() + vb = type_vectorbackend(element) + fem = type_fem(element.sub_elements()[0]) + dim = element.num_sub_elements() + cass = type_constraintsassembler(bool(is_dirichlet[0])) + return "using {} = Dune::PDELab::VectorGridFunctionSpace<{}, {}, {}, {}, {}, {}>;".format(name, gv, fem, dim, vb, vb, cass) + + +@preamble +def typedef_composite_gfs(element, name, subgfs): + vb = type_vectorbackend(element) + ot = type_orderingtag() + args = ", ".join(subgfs) + return "using {} = Dune::PDELab::CompositeGridFunctionSpace<{}, {}, {}>;".format(name, vb, ot, args) + + +@preamble +def define_blocksize(name, element): + from dune.perftool.pdelab.driver import isDG, isQuadrilateral + assert isDG(element) + assert isQuadrilateral(element.cell()) + dimension = get_dimension() + degree = element.degree() + return "static const int {} = Dune::QkStuff::QkSize<{}, {}>::value;".format(name, degree, dimension) + + +def name_blocksize(element): + name = "blocksize" + define_blocksize(name, element) + return name + + +@preamble +def typedef_vectorbackend(name, element): + include_file("dune/pdelab/backend/istl.hh", filetag="driver") + if get_option("fastdg"): + blocksize = name_blocksize(element) + return "using {} = Dune::PDELab::istl::VectorBackend<Dune::PDELab::istl::Blocking::fixed, {}>;".format(name, blocksize) + else: + return "using {} = Dune::PDELab::istl::VectorBackend<Dune::PDELab::istl::Blocking::none, 1>;".format(name) + + +def type_vectorbackend(element): + name = "VectorBackend" + typedef_vectorbackend(name, element) + return name + + +def type_orderingtag(): + return "Dune::PDELab::LexicographicOrderingTag" + + +@preamble +def typedef_dirichlet_constraintsassembler(name): + include_file("dune/pdelab/constraints/conforming.hh", filetag="driver") + return "using {} = Dune::PDELab::ConformingDirichletConstraints;".format(name) + + +@preamble +def typedef_no_constraintsassembler(name): + return "using {} = Dune::PDELab::NoConstraints;".format(name) + + +def type_constraintsassembler(is_dirichlet): + assert isinstance(is_dirichlet, bool) + if is_dirichlet: + name = "DirichletConstraintsAssember" + typedef_dirichlet_constraintsassembler(name) + return name + else: + name = "NoConstraintsAssembler" + typedef_no_constraintsassembler(name) + return name diff --git a/python/dune/perftool/pdelab/driver/gridoperator.py b/python/dune/perftool/pdelab/driver/gridoperator.py new file mode 100644 index 00000000..500d8bc7 --- /dev/null +++ b/python/dune/perftool/pdelab/driver/gridoperator.py @@ -0,0 +1,173 @@ +from dune.perftool.generation import (get_global_context_value, + include_file, + preamble, + ) +from dune.perftool.pdelab.driver import (form_name_suffix, + get_cell, + get_dimension, + get_test_element, + get_trial_element, + isQuadrilateral, + name_initree, + ) +from dune.perftool.pdelab.driver.constraints import (name_assembled_constraints, + type_constraintscontainer, + ) +from dune.perftool.pdelab.driver.gridfunctionspace import (name_test_gfs, + name_trial_gfs, + preprocess_leaf_data, + type_domainfield, + type_range, + type_test_gfs, + type_trial_gfs, + ) +from dune.perftool.pdelab.localoperator import localoperator_basename +from dune.perftool.pdelab.parameter import parameterclass_basename +from dune.perftool.options import get_option + + +@preamble +def typedef_gridoperator(name, formdata): + ugfs = type_trial_gfs() + vgfs = type_test_gfs() + lop = type_localoperator(formdata) + cc = type_constraintscontainer() + mb = type_matrixbackend() + df = type_domainfield() + r = type_range() + if get_option("fastdg"): + if not get_option("sumfact"): + raise PerftoolCodegenError("FastDGGridOperator is only implemented for sumfactorization.") + include_file("dune/pdelab/gridoperator/fastdg.hh", filetag="driver") + return "using {} = Dune::PDELab::FastDGGridOperator<{}, {}, {}, {}, {}, {}, {}, {}, {}>;".format(name, ugfs, vgfs, lop, mb, df, r, r, cc, cc) + else: + include_file("dune/pdelab/gridoperator/gridoperator.hh", filetag="driver") + return "using {} = Dune::PDELab::GridOperator<{}, {}, {}, {}, {}, {}, {}, {}, {}>;".format(name, ugfs, vgfs, lop, mb, df, r, r, cc, cc) + + +def type_gridoperator(formdata): + name = form_name_suffix("GO", formdata).upper() + typedef_gridoperator(name, formdata) + return name + + +@preamble +def define_gridoperator(name, formdata): + gotype = type_gridoperator(formdata) + ugfs = name_trial_gfs() + vgfs = name_test_gfs() + if ugfs != vgfs: + raise NotImplementedError("Non-Galerkin methods currently not supported!") + cc = name_assembled_constraints() + lop = name_localoperator(formdata) + mb = name_matrixbackend() + return ["{} {}({}, {}, {}, {}, {}, {});".format(gotype, name, ugfs, cc, vgfs, cc, lop, mb), + "std::cout << \"gfs with \" << {}.size() << \" dofs generated \"<< std::endl;".format(ugfs), + "std::cout << \"cc with \" << {}.size() << \" dofs generated \"<< std::endl;".format(cc)] + + +def name_gridoperator(formdata): + name = form_name_suffix("go", formdata) + define_gridoperator(name, formdata) + return name + + +@preamble +def typedef_localoperator(name, formdata): + ugfs = type_trial_gfs() + vgfs = type_test_gfs() + data = get_global_context_value("data") + filename = get_option("operator_file") + include_file(filename, filetag="driver") + lopname = localoperator_basename(formdata, data) + range_type = type_range() + return "using {} = {}<{}, {}, {}>;".format(name, lopname, ugfs, vgfs, range_type) + + +def type_localoperator(formdata): + name = form_name_suffix("LOP", formdata).upper() + typedef_localoperator(name, formdata) + return name + + +@preamble +def define_localoperator(name, formdata): + loptype = type_localoperator(formdata) + ini = name_initree() + params = name_parameters(formdata) + return "{} {}({}, {});".format(loptype, name, ini, params) + + +def name_localoperator(formdata): + name = form_name_suffix("lop", formdata) + define_localoperator(name, formdata) + return name + + +@preamble +def define_dofestimate(name): + # Provide a worstcase estimate for the number of entries per row based + # on the given gridfunction space and cell geometry + if isQuadrilateral(get_cell()): + geo_factor = 2**get_dimension() + else: + if get_dimension() < 3: + geo_factor = 3*get_dimension() + else: + # TODO no idea how a generic estimate for 3D simplices looks like + geo_factor = 12 + + gfs = name_trial_gfs() + ini = name_initree() + + return ["int generic_dof_estimate = {} * {}.maxLocalSize();".format(geo_factor, gfs), + "int {} = {}.get<int>(\"istl.number_of_nnz\", generic_dof_estimate);".format(name, ini)] + + +def name_dofestimate(): + name = "dofestimate" + define_dofestimate(name) + return name + + +@preamble +def typedef_matrixbackend(name): + include_file("dune/pdelab/backend/istl.hh", filetag="driver") + return "using {} = Dune::PDELab::istl::BCRSMatrixBackend<>;".format(name) + + +def type_matrixbackend(): + name = "MatrixBackend" + typedef_matrixbackend(name) + return name + + +@preamble +def define_matrixbackend(name): + mbtype = type_matrixbackend() + dof = name_dofestimate() + return "{} {}({});".format(mbtype, name, dof) + + +def name_matrixbackend(): + name = "mb" + define_matrixbackend(name) + return name + + +def type_parameters(formdata): + data = get_global_context_value("data") + name = parameterclass_basename(formdata, data) + return name + + +@preamble +def define_parameters(name, formdata): + partype = type_parameters(formdata) + return "{} {};".format(partype, name) + + +def name_parameters(formdata): + name = form_name_suffix("params", formdata) + define_parameters(name, formdata) + return name diff --git a/python/dune/perftool/pdelab/driver/instationary.py b/python/dune/perftool/pdelab/driver/instationary.py new file mode 100644 index 00000000..bf8759e7 --- /dev/null +++ b/python/dune/perftool/pdelab/driver/instationary.py @@ -0,0 +1,213 @@ +from dune.perftool.generation import preamble +from dune.perftool.pdelab.driver import (get_formdata, + is_linear, + ) +from dune.perftool.pdelab.driver.gridoperator import (type_gridoperator,) +from dune.perftool.pdelab.driver.solve import (print_matrix, + print_residual, + ) +from dune.perftool.options import get_option + + +def solve_instationary(): + # Test if form is linear in ansatzfunction + linear = is_linear() + + # Test wether we want to do matrix free operator evaluation + matrix_free = get_option('matrix_free') + + # Create time loop + if linear and matrix_free: + assert False + elif linear and not matrix_free: + time_loop() + if not linear and matrix_free: + assert False + elif not linear and not matrix_free: + assert False + + 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 +def time_loop(): + ini = name_initree() + 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) + vector_type = type_vector(formdata) + vector = name_vector(formdata) + + # Choose between explicit and implicit time stepping + explicit = get_option('explicit_time_stepping') + if explicit: + osm = name_explicitonestepmethod() + apply_call = "{}.apply(time, dt, {}, {}new);".format(osm, vector, vector) + else: + boundary = name_boundary_function(expr) + osm = name_onestepmethod() + apply_call = "{}.apply(time, dt, {}, {}, {}new);".format(osm, vector, boundary, vector) + + # Setup visualization + visualize_initial_condition() + vtk_sequence_writer = name_vtk_sequence_writer() + + return ["", + "double T = {}.get<double>(\"instat.T\", 1.0);".format(ini), + "double dt = {}.get<double>(\"instat.dt\", 0.1);".format(ini), + "while (time<T-1e-8){", + " // Assemble constraints for new time step", + " {}.setTime({}+dt);".format(params, time), + " Dune::PDELab::constraints({}, {}, {});".format(bctype, gfs, cc), + "", + " // Do time step", + " {} {}new({});".format(vector_type, vector, vector), + " {}".format(apply_call), + "", + " // Accept new time step", + " {} = {}new;".format(vector, vector), + " time += dt;", + "", + " // Output to VTK File", + " {}.write({}, Dune::VTK::appendedraw);".format(vtk_sequence_writer, time), + "}", + ""] + + +@preamble +def define_time(name): + return "double {} = 0.0;".format(name) + + +def name_time(): + define_time("time") + return "time" + + + +@preamble +def typedef_timesteppingmethod(name): + r_type = type_range() + explicit = get_option('explicit_time_stepping') + if explicit: + return "using {} = Dune::PDELab::ExplicitEulerParameter<{}>;".format(name, r_type) + else: + return "using {} = Dune::PDELab::OneStepThetaParameter<{}>;".format(name, r_type) + + +def type_timesteppingmethod(): + typedef_timesteppingmethod("TSM") + return "TSM" + + +@preamble +def define_timesteppingmethod(name): + tsm_type = type_timesteppingmethod() + explicit = get_option('explicit_time_stepping') + if explicit: + return "{} {};".format(tsm_type, name) + else: + return "{} {}(1.0);".format(tsm_type, name) + + +def name_timesteppingmethod(): + define_timesteppingmethod("tsm") + return "tsm" + + +@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']) + explicit = get_option('explicit_time_stepping') + if explicit: + return "using {} = Dune::PDELab::OneStepGridOperator<{},{},false>;".format(name, go_type, mass_go_type) + else: + return "using {} = Dune::PDELab::OneStepGridOperator<{},{}>;".format(name, go_type, mass_go_type) + + +def type_instationarygridoperator(): + typedef_instationarygridoperator("IGO") + return "IGO" + + +@preamble +def define_instationarygridoperator(name): + igo_type = type_instationarygridoperator() + go = name_gridoperator(_driver_data['formdata']) + mass_go = name_gridoperator(_driver_data['mass_formdata']) + return "{} {}({}, {});".format(igo_type, name, go, mass_go) + + +def name_instationarygridoperator(): + define_instationarygridoperator("igo") + return "igo" + + +@preamble +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']) + return "using {} = Dune::PDELab::OneStepMethod<{}, {}, {}, {}, {}>;".format(name, r_type, igo_type, snp_type, vector_type, vector_type) + + +def type_onestepmethod(): + typedef_onestepmethod("OSM") + return "OSM" + + +@preamble +def define_onestepmethod(name): + ilptype = type_onestepmethod() + tsm = name_timesteppingmethod() + igo_type = type_instationarygridoperator() + igo = name_instationarygridoperator() + snp = name_stationarynonlinearproblemsolver(igo_type, igo) + return "{} {}({},{},{});".format(ilptype, name, tsm, igo, snp) + + +def name_onestepmethod(): + define_onestepmethod("osm") + return "osm" + + +@preamble +def typedef_explicitonestepmethod(name): + r_type = type_range() + igo_type = type_instationarygridoperator() + ls_type = type_linearsolver() + vector_type = type_vector(_driver_data['formdata']) + return "using {} = Dune::PDELab::ExplicitOneStepMethod<{}, {}, {}, {}>;".format(name, r_type, igo_type, ls_type, vector_type) + + +def type_explicitonestepmethod(): + typedef_explicitonestepmethod("EOSM") + return "EOSM" + + +@preamble +def define_explicitonestepmethod(name): + eosm_type = type_explicitonestepmethod() + tsm = name_timesteppingmethod() + igo = name_instationarygridoperator() + ls = name_linearsolver() + return "{} {}({}, {}, {});".format(eosm_type, name, tsm, igo, ls) + + +def name_explicitonestepmethod(): + define_explicitonestepmethod("eosm") + return "eosm" diff --git a/python/dune/perftool/pdelab/driver/interpolate.py b/python/dune/perftool/pdelab/driver/interpolate.py new file mode 100644 index 00000000..424388a0 --- /dev/null +++ b/python/dune/perftool/pdelab/driver/interpolate.py @@ -0,0 +1,115 @@ +from dune.perftool.generation import (cached, + get_counted_variable, + global_context, + include_file, + preamble, + ) +from dune.perftool.pdelab.driver import (FEM_name_mangling, + get_formdata, + get_trial_element, + is_stationary, + preprocess_leaf_data, + ) +from dune.perftool.pdelab.driver.gridfunctionspace import (name_gfs, + name_leafview, + ) +from dune.perftool.pdelab.driver.gridoperator import (name_parameters,) + +from ufl import FiniteElement, MixedElement, TensorElement, VectorElement + + +def _do_interpolate(dirichlet): + if isinstance(dirichlet, (list, tuple)): + return any(bool(d) for d in dirichlet) + else: + return bool(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) + dirichlet = preprocess_leaf_data(element, "dirichlet_expression") + bf = name_boundary_function(element, dirichlet) + interpolate_vector(bf, gfs, name) + + +@preamble +def interpolate_vector(func, gfs, name): + return "Dune::PDELab::interpolate({}, {}, {});".format(func, + gfs, + name, + ) + + +def name_boundary_function(element, dirichlet): + if isinstance(element, MixedElement): + k = 0 + childs = [] + for subel in element.sub_elements(): + childs.append(name_boundary_function(subel, dirichlet[k:k + subel.value_size()])) + k = k + subel.value_size() + name = "_".join(childs) + define_composite_boundary_function(name, childs) + return name + else: + assert isinstance(element, FiniteElement) + name = "{}_boundary".format(FEM_name_mangling(element).lower()) + define_boundary_function(name, dirichlet[0]) + return name + + +@preamble +def define_compositegfs_parameterfunction(name, children): + return "Dune::PDELab::CompositeGridFunction<{}> {}({});".format(', '.join('decltype({})'.format(c) for c in children), + name, + ', '.join(children)) + + +@preamble +def define_boundary_function(name, dirichlet): + gv = name_leafview() + lambdaname = name_boundary_lambda(dirichlet) + include_file('dune/pdelab/function/callableadapter.hh', filetag='driver') + if is_stationary(): + return "auto {} = Dune::PDELab::makeGridFunctionFromCallable({}, {});".format(name, + gv, + lambdaname, + ) + else: + params = name_parameters(get_formdata()) + return "auto {} = Dune::PDELab::makeInstationaryGridFunctionFromCallable({}, {}, {});".format(name, + gv, + lambdaname, + params) + + +@cached +def name_boundary_lambda(boundary): + name = get_counted_variable("lambda") + define_boundary_lambda(name, boundary) + return name + + +@preamble +def define_boundary_lambda(name, boundary): + from dune.perftool.ufl.execution import Expression + from ufl.classes import Expr + if boundary is None: + return "auto {} = [&](const auto& x){{ return 0.0; }};".format(name) + elif isinstance(boundary, Expression): + if boundary.is_global: + return "auto {} = [&](const auto& x){{ {} }};".format(name, boundary.c_expr[0]) + else: + return "auto {} = [&](const auto& e, const auto& x){{ {} }};".format(name, boundary.c_expr[0]) + elif isinstance(boundary, Expr): + # Set up a visitor + with global_context(integral_type="exterior_facet", formdata=get_formdata(), driver=True): + from dune.perftool.ufl.visitor import UFL2LoopyVisitor + from dune.perftool.pdelab import PDELabInterface + visitor = UFL2LoopyVisitor(PDELabInterface(), "exterior_facet", {}) + from dune.perftool.loopy.target import numpy_to_cpp_dtype + return "auto {} = [&](const auto& x){{ return ({}){}; }};".format(name, + numpy_to_cpp_dtype("float64"), + visitor(boundary)) diff --git a/python/dune/perftool/pdelab/driver/solve.py b/python/dune/perftool/pdelab/driver/solve.py new file mode 100644 index 00000000..5e602827 --- /dev/null +++ b/python/dune/perftool/pdelab/driver/solve.py @@ -0,0 +1,245 @@ +from dune.perftool.generation import (include_file, + preamble, + ) +from dune.perftool.options import get_option +from dune.perftool.pdelab.driver import (form_name_suffix, + get_formdata, + is_linear, + name_initree, + ) +from dune.perftool.pdelab.driver.gridfunctionspace import name_trial_gfs +from dune.perftool.pdelab.driver.gridoperator import (name_gridoperator, + type_gridoperator, + ) +from dune.perftool.pdelab.driver.interpolate import interpolate_dirichlet_data + + +@preamble +def dune_solve(): + # Test if form is linear in ansatzfunction + linear = is_linear() + + # Test wether we want to do matrix free operator evaluation + matrix_free = get_option('matrix_free') + + # Get right solve command + if linear and matrix_free: + formdata = get_formdata() + go = name_gridoperator(formdata) + x = name_vector(formdata) + include_file("dune/perftool/matrixfree.hh", filetag="driver") + solve = "solveMatrixFree({},{});".format(go, x) + elif linear and not matrix_free: + slp = name_stationarylinearproblemsolver() + solve = "{}.apply();".format(slp) + elif not linear and matrix_free: + # TODO copy of linear case and obviously broken, used to generate something ;) + formdata = get_formdata() + go = name_gridoperator(formdata) + x = name_vector(formdata) + include_file("dune/perftool/matrixfree.hh", filetag="driver") + solve = "solveNonlinearMatrixFree({},{});".format(go, x) + elif not linear and not matrix_free: + go_type = type_gridoperator(_driver_data['formdata']) + go = name_gridoperator(_driver_data['formdata']) + snp = name_stationarynonlinearproblemsolver(go_type, go) + solve = "{}.apply();".format(snp) + + 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() + + if get_option('instrumentation_level') >= 2: + from dune.perftool.pdelab.driver.timings import setup_timer, name_timing_stream + setup_timer() + from dune.perftool.generation import post_include + post_include("HP_DECLARE_TIMER(solve);", filetag="driver") + + # Print times after solving + from dune.perftool.generation import get_global_context_value + formdatas = get_global_context_value("formdatas") + print_times = [] + for formdata in formdatas: + from dune.perftool.pdelab.driver.gridoperator import name_localoperator + lop_name = name_localoperator(formdata) + timestream = name_timing_stream() + print_times.append("{}.dump_timers({}, {}, true);".format(lop_name, timestream, name_timing_identifier())) + + solve = ["HP_TIMER_START(solve);", + "{}".format(solve), + "HP_TIMER_STOP(solve);", + "DUMP_TIMER(solve, {}, true);".format(timestream), + ] + if get_option('instrumentation_level') >= 3: + solve.extend(print_times) + + return solve + + +def name_vector(formdata): + name = form_name_suffix("x", formdata) + define_vector(name, formdata) + interpolate_dirichlet_data(name) + return name + + +@preamble +def typedef_vector(name, formdata): + go_type = type_gridoperator(formdata) + return "using {} = {}::Traits::Domain;".format(name, go_type) + + +def type_vector(formdata): + name = form_name_suffix("V", formdata).upper() + typedef_vector(name, formdata) + return name + + +@preamble +def define_vector(name, formdata): + vtype = type_vector(formdata) + gfs = name_trial_gfs() + return ["{} {}({});".format(vtype, name, gfs), "{} = 0.0;".format(name)] + + + +@preamble +def typedef_linearsolver(name): + include_file("dune/pdelab/backend/istl.hh", filetag="driver") + return "using {} = Dune::PDELab::ISTLBackend_SEQ_UMFPack;".format(name) + + +def type_linearsolver(): + name = "LinearSolver" + typedef_linearsolver(name) + return name + + +@preamble +def define_linearsolver(name): + lstype = type_linearsolver() + return "{} {}(false);".format(lstype, name) + + +def name_linearsolver(): + name = "ls" + define_linearsolver(name) + return name + + +@preamble +def define_reduction(name): + ini = name_initree() + return "double {} = {}.get<double>(\"reduction\", 1e-12);".format(name, ini) + + +def name_reduction(): + name = "reduction" + define_reduction(name) + return name + + +@preamble +def typedef_stationarylinearproblemsolver(name): + include_file("dune/pdelab/stationary/linearproblem.hh", filetag="driver") + gotype = type_gridoperator(get_formdata()) + lstype = type_linearsolver() + xtype = type_vector(get_formdata()) + return "using {} = Dune::PDELab::StationaryLinearProblemSolver<{}, {}, {}>;".format(name, gotype, lstype, xtype) + + +def type_stationarylinearproblemsolver(): + typedef_stationarylinearproblemsolver("SLP") + return "SLP" + + +@preamble +def define_stationarylinearproblemsolver(name): + slptype = type_stationarylinearproblemsolver() + formdata = get_formdata() + go = name_gridoperator(formdata) + ls = name_linearsolver() + x = name_vector(formdata) + red = name_reduction() + return "{} {}({}, {}, {}, {});".format(slptype, name, go, ls, x, red) + + +def name_stationarylinearproblemsolver(): + define_stationarylinearproblemsolver("slp") + return "slp" + + +@preamble +def typedef_stationarynonlinearproblemsolver(name, go_type): + include_file("dune/pdelab/newton/newton.hh", filetag="driver") + ls_type = type_linearsolver() + x_type = type_vector(_driver_data['formdata']) + return "using {} = Dune::PDELab::Newton<{}, {}, {}>;".format(name, go_type, ls_type, x_type) + + +def type_stationarynonlinearproblemssolver(go_type): + name = "SNP" + typedef_stationarynonlinearproblemsolver(name, go_type) + return name + + +@preamble +def define_stationarynonlinearproblemsolver(name, go_type, go): + snptype = type_stationarynonlinearproblemssolver(go_type) + x = name_vector(get_formdata()) + ls = name_linearsolver() + return "{} {}({}, {}, {});".format(snptype, name, go, x, ls) + + +def name_stationarynonlinearproblemsolver(go_type, go): + name = "snp" + define_stationarynonlinearproblemsolver(name, go_type, go) + return name + + +@preamble +def print_residual(): + ini = name_initree() + formdata = get_formdata() + n_go = name_gridoperator(formdata) + v = name_vector(formdata) + t_v = type_vector(formdata) + include_file("random", system=True, filetag="driver") + + return ["if ({}.get<bool>(\"printresidual\", false)) {{".format(ini), + " using Dune::PDELab::Backend::native;", + " {} r({});".format(t_v, v), + " // Setup random input", + " std::size_t seed = 0;", + " auto rng = std::mt19937_64(seed);", + " auto dist = std::uniform_real_distribution<>(-1., 1.);", + " for (auto& v : {})".format(v), + " v = dist(rng);", + " r=0.0;", + " {}.residual({}, r);".format(n_go, v), + " Dune::printvector(std::cout, native(r), \"residual vector\", \"row\");", + "}"] + + +@preamble +def print_matrix(): + formdata = get_formdata() + ini = name_initree() + t_go = type_gridoperator(formdata) + n_go = name_gridoperator(formdata) + v = name_vector(formdata) + t_v = type_vector(formdata) + + return ["if ({}.get<bool>(\"printmatrix\", false)) {{".format(ini), + " using M = typename {}::Traits::Jacobian;".format(t_go), + " M m({});".format(n_go), + " {}.jacobian({},m);".format(n_go, v), + " using Dune::PDELab::Backend::native;", + " Dune::printmatrix(std::cout, native(m),\"global stiffness matrix\",\"row\",9,1);", + "}"] diff --git a/python/dune/perftool/pdelab/driver/vtk.py b/python/dune/perftool/pdelab/driver/vtk.py new file mode 100644 index 00000000..2f68140e --- /dev/null +++ b/python/dune/perftool/pdelab/driver/vtk.py @@ -0,0 +1,151 @@ +from dune.perftool.generation import (include_file, + preamble, + ) +from dune.perftool.pdelab.driver import (get_formdata, + get_trial_element, + name_initree, + ) +from dune.perftool.pdelab.driver.gridfunctionspace import (name_leafview, + name_trial_gfs, + type_leafview, + ) +from dune.perftool.pdelab.driver.solve import name_vector + + +@preamble +def define_vtkfile(name): + ini = name_initree() + include_file("string", filetag="driver") + return "std::string {} = {}.get<std::string>(\"wrapper.vtkcompare.name\", \"output\");".format(name, ini) + + +def name_vtkfile(): + define_vtkfile("vtkfile") + return "vtkfile" + + +@preamble +def typedef_vtkwriter(name): + include_file("dune/grid/io/file/vtk/subsamplingvtkwriter.hh", filetag="driver") + gv = type_leafview() + return "using {} = Dune::SubsamplingVTKWriter<{}>;".format(name, gv) + + +def type_vtkwriter(): + typedef_vtkwriter("VTKWriter") + return "VTKWriter" + + +@preamble +def define_subsamplinglevel(name): + ini = name_initree() + return "int {} = {}.get<int>(\"vtk.subsamplinglevel\", 0);".format(name, ini) + + +def name_subsamplinglevel(): + define_subsamplinglevel("sublevel") + return "sublevel" + + +@preamble +def define_vtkwriter(name): + _type = type_vtkwriter() + gv = name_leafview() + subsamp = name_subsamplinglevel() + return "{} {}({}, {});".format(_type, name, gv, subsamp) + + +def name_vtkwriter(): + define_vtkwriter("vtkwriter") + return "vtkwriter" + + +@preamble +def vtkoutput(): + include_file("dune/pdelab/gridfunctionspace/vtk.hh", filetag="driver") + vtkwriter = name_vtkwriter() + gfs = name_trial_gfs() + vtkfile = name_vtkfile() + predicate = name_predicate() + vec = name_vector(get_formdata()) + + return ["Dune::PDELab::addSolutionToVTKWriter({}, {}, {}, Dune::PDELab::vtk::defaultNameScheme(), {});".format(vtkwriter, gfs, vec, predicate), + "{}.write({}, Dune::VTK::ascii);".format(vtkwriter, vtkfile)] + + +def type_predicate(): + include_file("dune/perftool/vtkpredicate.hh", filetag="driver") + return "CuttingPredicate" + + +@preamble +def define_predicate(name): + t = type_predicate() + return "{} {};".format(t, name) + + +def name_predicate(): + define_predicate("predicate") + return "predicate" + + + +@preamble +def typedef_vtk_sequence_writer(name): + include_file("dune/grid/io/file/vtk/vtksequencewriter.hh", filetag="driver") + gv_type = type_leafview() + return "using {} = Dune::VTKSequenceWriter<{}>;".format(name, gv_type) + + +def type_vtk_sequence_writer(): + typedef_vtk_sequence_writer("VTKSW") + return "VTKSW" + + +@preamble +def define_vtk_sequence_writer(name): + vtksw_type = type_vtk_sequence_writer() + vtkw_type = type_vtkwriter() + vtkw = name_vtkwriter() + vtkfile = name_vtkfile() + return "{} {}(std::make_shared<{}>({}), {});".format(vtksw_type, name, vtkw_type, vtkw, vtkfile) + + +def name_vtk_sequence_writer(): + define_vtk_sequence_writer("vtkSequenceWriter") + return "vtkSequenceWriter" + + +@preamble +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_gfs(element) + vector = name_vector(get_formdata()) + predicate = name_predicate() + from dune.perftool.pdelab.driver.instationary import name_time + 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 diff --git a/python/dune/perftool/ufl/execution.py b/python/dune/perftool/ufl/execution.py index 9e857d97..0f753451 100644 --- a/python/dune/perftool/ufl/execution.py +++ b/python/dune/perftool/ufl/execution.py @@ -9,16 +9,6 @@ import ufl from ufl import * -# Monkey patch to the FiniteElementBase -# We want to subclass finite elements in order to allow meta data -# connected to constraints. This is an intermediate solution until -# we have a proper notion of (global) function spaces in UFL. As is, -# two finite elements with different meta data would not compare equally, -# but they should in order to allow hashing generation magic based on -# them (as done everywhere) -ufl.FiniteElementBase.__eq__ = lambda s, o: repr(s) == repr(o) - - class TrialFunction(ufl.Coefficient): """ A coefficient that always takes the reserved index 0 """ def __init__(self, element, count=None): @@ -136,51 +126,3 @@ def split_expression(expr): element=expr.element.sub_elements()[i]) for i in range(expr.element.num_sub_elements()) ) - - -class FiniteElement(ufl.FiniteElement): - - __slots = ufl.FiniteElement.__slots__ + ["dirichlet_expression", "dirichlet_constraints"] - - def __new__(cls, *args, **kwargs): - kwargs.pop('dirichlet_constraints', None) - kwargs.pop('dirichlet_expression', None) - return ufl.FiniteElement.__new__(cls, *args, **kwargs) - - def __init__(self, *args, **kwargs): - if ('dirichlet_constraints' in kwargs) or ('dirichlet_expression' in kwargs): - # Get dirichlet_constraints and convert it to Expression if necessary! - self.dirichlet_constraints = kwargs.pop('dirichlet_constraints', 'return true;') - if isinstance(self.dirichlet_constraints, str): - self.dirichlet_constraints = Expression(self.dirichlet_constraints) - from ufl.classes import Expr - assert isinstance(self.dirichlet_constraints, (Expression, Expr)) - - # Get dirichlet_constraints and convert it to Expression if necessary! - self.dirichlet_expression = kwargs.pop('dirichlet_expression', 'return 0.0;') - if isinstance(self.dirichlet_expression, str): - self.dirichlet_expression = Expression(self.dirichlet_expression) - assert isinstance(self.dirichlet_expression, (Expression, Expr)) - - # Initialize the original finite element from ufl - ufl.FiniteElement.__init__(self, *args, **kwargs) - - -class VectorElement(ufl.VectorElement): - def __init__(self, *args, **kwargs): - if ('dirichlet_constraints' in kwargs) or ('dirichlet_expression' in kwargs): - # Get dirichlet_constraints and convert it to Expression if necessary! - self.dirichlet_constraints = kwargs.pop('dirichlet_constraints', 'return true;') - if isinstance(self.dirichlet_constraints, str): - self.dirichlet_constraints = Expression(self.dirichlet_constraints) - from ufl.classes import Expr - assert isinstance(self.dirichlet_constraints, (Expression, Expr)) - - # Get dirichlet_constraints and convert it to Expression if necessary! - self.dirichlet_expression = kwargs.pop('dirichlet_expression', 'return 0.0;') - if isinstance(self.dirichlet_expression, str): - self.dirichlet_expression = Expression(self.dirichlet_expression) - assert isinstance(self.dirichlet_expression, (Expression, Expr)) - - # Initialize the original finite element from ufl - ufl.VectorElement.__init__(self, *args, **kwargs) diff --git a/test/poisson/poisson.mini b/test/poisson/poisson.mini index 063be404..3597ac05 100644 --- a/test/poisson/poisson.mini +++ b/test/poisson/poisson.mini @@ -13,5 +13,4 @@ extension = vtu [formcompiler] numerical_jacobian = 1, 0 | expand num -exact_solution_expression = g compare_l2errorsquared = 1e-7 diff --git a/test/poisson/poisson.ufl b/test/poisson/poisson.ufl index 73515675..2bfe3313 100644 --- a/test/poisson/poisson.ufl +++ b/test/poisson/poisson.ufl @@ -6,9 +6,12 @@ c = (0.5-x[0])**2 + (0.5-x[1])**2 g = exp(-1.*c) f = 4*(1.-c)*g -V = FiniteElement("CG", cell, 1, dirichlet_expression=g) +V = FiniteElement("CG", cell, 1) u = TrialFunction(V) v = TestFunction(V) forms = [(inner(grad(u), grad(v)) - f*v)*dx] +exact_solution = g +dirichlet_expression = g +is_dirichlet = 1 \ No newline at end of file -- GitLab