diff --git a/python/dune/codegen/pdelab/driver/constraints.py b/python/dune/codegen/pdelab/driver/constraints.py index aed658caaa1fef5bef7bcb0615f6383efcdf8d3a..344294a183006b072016a8b414de90742ca8d4cd 100644 --- a/python/dune/codegen/pdelab/driver/constraints.py +++ b/python/dune/codegen/pdelab/driver/constraints.py @@ -15,6 +15,7 @@ from dune.codegen.pdelab.driver.gridfunctionspace import (name_gfs, type_trial_gfs, preprocess_leaf_data, ) +from dune.codegen.pdelab.driver.interpolate import name_grid_function_root from ufl.classes import Expr from ufl import FiniteElement, MixedElement, TensorElement, VectorElement, TensorProductElement @@ -43,7 +44,7 @@ def assemble_constraints(name): gfs = name_trial_gfs() is_dirichlet = preprocess_leaf_data(element, "is_dirichlet") if has_dirichlet_constraints(is_dirichlet): - bctype_function = name_bctype_grid_function(element, is_dirichlet) + bctype_function = name_grid_function_root("is_dirichlet") return "Dune::PDELab::constraints(*{}, *{}, *{});".format(bctype_function, gfs, name,) @@ -53,118 +54,7 @@ def assemble_constraints(name): # -# Bctype lambda -# - - -def bctype_lambda(func, local=False): - from ufl.classes import Expr - if func is None: - func = 0.0 - if isinstance(func, (int, float)): - return "[&](const auto& is, const auto& xl){{ return {}; }}".format(float(func)) - elif isinstance(func, Expr): - from dune.codegen.pdelab.driver.visitor import ufl_to_code - return "[&](const auto& is, const auto& xl){{ {}; }}".format(ufl_to_code(func)) - raise ValueError("Expression not understood") - - -# -# Bctype function -# -# std::function that will be used to create the bctype grid function - - -@class_member(classtag="driver_block") -def typedef_bctype_function(name): - leafview_type = type_leafview() - entity = "typename {}::Intersection".format(leafview_type) - coordinate = "typename {}::Intersection::LocalCoordinate".format(leafview_type) - return "using {} = std::function<bool({}, {})>;".format(name, entity, coordinate) - - -def type_bctype_function(): - name = "BctypeFunction" - typedef_bctype_function(name) - return name - - -@class_member(classtag="driver_block") -def declare_bctype_function(name, element, is_dirichlet): - bctype_function_type = type_bctype_function() - return "std::shared_ptr<{}> {};".format(bctype_function_type, name) - - -@preamble(section="constriants", kernel="driver_block") -def define_bctype_function(name, element, is_dirichlet): - declare_bctype_function(name, element, is_dirichlet) - bctype_function_type = type_bctype_function() - bct_lambda = bctype_lambda(is_dirichlet) - return "{} = std::make_shared<{}> ({});".format(name, bctype_function_type, bct_lambda) - - -def name_bctype_function(element, is_dirichlet): - name = get_counted_variable("bctype_function") - define_bctype_function(name, element, is_dirichlet) - return name - - -# -# Bctype Grid Function -# -# GridFunction that returns 1 if the boundary is constraint (else 0) - - -@class_member(classtag="driver_block") -def typedef_bctype_grid_function(name): - bctype_function_type = type_bctype_function() - return "using {} = Dune::PDELab::LocalCallableToBoundaryConditionAdapter<{}>;".format(name, - bctype_function_type) - - -def type_bctype_grid_function(): - name = "BctypeGridFunction" - typedef_bctype_grid_function(name) - return name - - -@class_member(classtag="driver_block") -def declare_bctype_grid_function(name): - bctype_type = type_bctype_grid_function() - return "std::shared_ptr<{}> {};".format(bctype_type, name) - - -@preamble(section="constraints", kernel="driver_block") -def define_bctype_grid_function(name, element, is_dirichlet): - declare_bctype_grid_function(name) - bctype_type = type_bctype_grid_function() - bctype_function = name_bctype_function(element, is_dirichlet) - return "{} = std::make_shared<{}> (*{});".format(name, bctype_type, bctype_function) - - -def name_bctype_grid_function(element, is_dirichlet): - # Note: Previously, there was a separate code branch for VectorElement here, - # which was implemented through PDELabs Power constraints concept. - # However this completely fails if you have different constraints for - # the children of a VectorElement. We therefore omit this branch completely. - if isinstance(element, MixedElement): - k = 0 - childs = [] - for subel in element.sub_elements(): - childs.append(name_bctype_grid_function(subel, is_dirichlet[k:k + subel.value_size()])) - k = k + subel.value_size() - name = "{}".format("_".join(childs)) - define_composite_constraints_parameters(name, element, tuple(childs)) - return name - else: - assert isinstance(element, (FiniteElement, TensorProductElement)) - name = get_counted_variable("bctype_grid_function") - define_bctype_grid_function(name, element, is_dirichlet[0]) - return name - - -# -# Composite constraints parameter +# Composite constraints parameters # diff --git a/python/dune/codegen/pdelab/driver/gridoperator.py b/python/dune/codegen/pdelab/driver/gridoperator.py index 8d0001cab2c7451d68db31332b7ef200f236f0d5..cf8504c2652abd3a1104815de46257a7746c7f3a 100644 --- a/python/dune/codegen/pdelab/driver/gridoperator.py +++ b/python/dune/codegen/pdelab/driver/gridoperator.py @@ -101,6 +101,11 @@ def driver_block_get_gridoperator(form_ident, name=None): gridoperator_type = type_gridoperator(form_ident) if not name: name = name_gridoperator(form_ident) + if name == "go_mass": + return ["std::shared_ptr<{}> getMassGridOperator(){{".format(gridoperator_type), + " return {};".format(name), + "}"] + return ["std::shared_ptr<{}> getGridOperator(){{".format(gridoperator_type), " return {};".format(name), "}"] @@ -154,6 +159,36 @@ def define_localoperator(name, form_ident): def name_localoperator(form_ident): name = "lop_{}".format(form_ident) define_localoperator(name, form_ident) + driver_block_get_localoperator(form_ident, name=name) + return name + + +@class_member(classtag="driver_block") +def driver_block_get_localoperator(form_ident, name=None): + if not name: + name = name_localoperator(form_ident) + localoperator_type = type_localoperator(form_ident) + method_name = "getLocalOperator" + if form_ident == "mass": + method_name = "getLocalMassOperator" + return ["std::shared_ptr<{}> {}(){{".format(localoperator_type, method_name), + " return {};".format(name), + "}"] + + +@preamble(section="postprocessing", kernel="main") +def main_define_localoperator(name, form_ident): + driver_block_name = name_driver_block() + driver_block_get_localoperator(form_ident) + method_name = "getLocalOperator" + if form_ident == "mass": + method_name = "getLocalMassOperator" + return "auto {} = {}.{}();".format(name, driver_block_name, method_name) + + +def main_name_localoperator(form_ident): + name = "localOperator{}".format(form_ident.capitalize()) + main_define_localoperator(name, form_ident) return name diff --git a/python/dune/codegen/pdelab/driver/instationary.py b/python/dune/codegen/pdelab/driver/instationary.py index c8edb4747fedee22a4c27612b5794aa29c32cc0f..51d20766c4ffb0a3dbe3ab3f3328aa2bce8d9de2 100644 --- a/python/dune/codegen/pdelab/driver/instationary.py +++ b/python/dune/codegen/pdelab/driver/instationary.py @@ -1,4 +1,5 @@ -from dune.codegen.generation import (include_file, +from dune.codegen.generation import (class_member, + include_file, preamble, ) from dune.codegen.pdelab.driver import (get_form_ident, @@ -12,7 +13,7 @@ from dune.codegen.pdelab.driver.gridfunctionspace import (name_trial_gfs, ) from dune.codegen.pdelab.driver.gridoperator import (name_gridoperator, type_gridoperator, - name_localoperator, + main_name_localoperator, ) from dune.codegen.pdelab.driver.constraints import (has_dirichlet_constraints, name_bctype_grid_function, @@ -23,6 +24,8 @@ from dune.codegen.pdelab.driver.interpolate import (interpolate_dirichlet_data, ) from dune.codegen.pdelab.driver.solve import (print_matrix, print_residual, + main_name_vector, + main_type_vector, name_linearsolver, name_stationarynonlinearproblemsolver, name_vector, @@ -44,18 +47,17 @@ def solve_instationary(): raise NotImplementedError("Instationary matrix free not implemented!") else: time_loop() - print_residual() print_matrix() -@preamble(section="instat") +@preamble(section="instat", kernel="main") def time_loop(): ini = name_initree() - lop = name_localoperator(get_form_ident()) + lop = main_name_localoperator(get_form_ident()) time = name_time() element = get_trial_element() - vector_type = type_vector(get_form_ident()) + vector_type = main_type_vector(get_form_ident()) vector = name_vector(get_form_ident()) interpolate_dirichlet_data(vector) gfs = name_trial_gfs() @@ -66,7 +68,7 @@ def time_loop(): bctype = name_bctype_grid_function(element, is_dirichlet) cc = name_constraintscontainer() assemble_new_constraints = (" // Assemble constraints for new time step\n" - " {}.setTime({}+dt);\n" + " {}->setTime({}+dt);\n" " Dune::PDELab::constraints({}, {}, {});\n" "\n".format(lop, time, bctype, gfs, cc) ) @@ -79,7 +81,7 @@ def time_loop(): else: osm = name_onestepmethod() if has_dirichlet_constraints(is_dirichlet): - boundary = name_boundary_grid_function_root("interpolate_expression") + boundary = name_grid_function_root("interpolate_expression") apply_call = "{}.apply(time, dt, {}, {}, {}new);".format(osm, vector, boundary, vector) else: apply_call = "{}.apply(time, dt, {}, {}new);".format(osm, vector, vector) @@ -117,7 +119,7 @@ def time_loop(): ""] -@preamble(section="init") +@preamble(section="init", kernel="main") def define_time(name): return "double {} = 0.0;".format(name) @@ -157,19 +159,26 @@ def type_timesteppingmethod(): return "TSM" -@preamble(section="instat") +@class_member(classtag="driver_block") +def declare_timesteppingmethod(name): + tsm_type = type_timesteppingmethod() + return "std::shared_ptr<{}> {};".format(tsm_type, name) + + +@preamble(section="instat", kernel="driver_block") def define_timesteppingmethod(name): + declare_timesteppingmethod(name) tsm_type = type_timesteppingmethod() explicit = get_option('explicit_time_stepping') if explicit: - return "{} {};".format(tsm_type, name) + return "{} = std::make_shared<{}>();".format(name, tsm_type) else: order = get_option('time_stepping_order') if order == 1: ini = name_initree() - return "{} {}({}.get<double>(\"instat.theta\",1.0));".format(tsm_type, name, ini) + return "{} = std::make_shared<{}>({}.get<double>(\"instat.theta\",1.0));".format(name, tsm_type, ini) else: - return "{} {};".format(tsm_type, name) + return "{} = std::make_shared<{}>();".format(name, tsm_type) def name_timesteppingmethod(): @@ -194,12 +203,19 @@ def type_instationarygridoperator(): return "IGO" -@preamble(section="gridoperator") +@class_member(classtag="driver_block") +def declare_instationarygridoperator(name): + igo_type = type_instationarygridoperator() + return "std::shared_ptr<{}> {};".format(igo_type, name) + + +@preamble(section="gridoperator", kernel="driver_block") def define_instationarygridoperator(name): + declare_instationarygridoperator(name) igo_type = type_instationarygridoperator() go = name_gridoperator(get_form_ident()) mass_go = name_gridoperator("mass") - return "{} {}({}, {});".format(igo_type, name, go, mass_go) + return "{} = std::make_shared<{}>({}, {});".format(name, igo_type, go, mass_go) def name_instationarygridoperator(): @@ -221,14 +237,21 @@ def type_onestepmethod(): return "OSM" -@preamble(section="instat") +@class_member(classtag="driver_block") +def declare_onestepmethod(name): + ilptype = type_onestepmethod() + return "std::shared_ptr<{}> {};".format(ilptype, name) + + +@preamble(section="instat", kernel="driver_block") def define_onestepmethod(name): + declare_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) + return "{} = std::make_shared<{}>({},{},{});".format(name, ilptype, tsm, igo, snp) def name_onestepmethod(): @@ -250,13 +273,20 @@ def type_explicitonestepmethod(): return "EOSM" -@preamble(section="instat") +@class_member(classtag="driver_block") +def declare_explicitonestepmethod(name): + eosm_type = type_explicitonestepmethod() + return "std::shared_ptr<{}> {};".format(eosm_type, name) + + +@preamble(section="instat", kernel="driver_block") def define_explicitonestepmethod(name): + declare_explicitonestepmethod(name) eosm_type = type_explicitonestepmethod() tsm = name_timesteppingmethod() igo = name_instationarygridoperator() ls = name_linearsolver() - return "{} {}({}, {}, {});".format(eosm_type, name, tsm, igo, ls) + return "{} = std::make_shared<{}>({}, {}, {});".format(name, eosm_type, tsm, igo, ls) def name_explicitonestepmethod(): diff --git a/python/dune/codegen/pdelab/driver/interpolate.py b/python/dune/codegen/pdelab/driver/interpolate.py index 6a52f485efd93ee43c217ecddd46104b18d8840d..15efff4ba60040c0b972d1e7a4bd79794300ebec 100644 --- a/python/dune/codegen/pdelab/driver/interpolate.py +++ b/python/dune/codegen/pdelab/driver/interpolate.py @@ -1,3 +1,12 @@ +"""Create grid functions + +Create all kinds of grid functions. This includes grid functions for the +boundary condition ('interpolate expression') the exact solution +('exact_solution') and the grid function that decides where Dirichlet boundary +conditions are applied ('is_dirichlet') +""" + + from dune.codegen.generation import (cached, class_member, get_counted_variable, @@ -40,13 +49,15 @@ def interpolate_dirichlet_data(name): def _grid_function_root_type(identifier): name_dict = {"exact_solution": "ExactSolution", - "interpolate_expression": "BoundaryGridFunction"} + "interpolate_expression": "BoundaryGridFunction", + "is_dirichlet": "BoundaryConditionType"} return name_dict[identifier] def _grid_function_root_name(identifier): name_dict = {"exact_solution": "exactSolution", - "interpolate_expression": "boundaryGridFunction"} + "interpolate_expression": "boundaryGridFunction", + "is_dirichlet": "boundaryConditionType"} return name_dict[identifier] @@ -56,18 +67,29 @@ def _get_grid_function_method_name(identifier): return name_dict[identifier] +# +# Composite grid function +# + + @class_member(classtag="driver_block") -def typedef_composite_grid_function(name, children): +def typedef_composite_grid_function(name, identifier, children): templates = ','.join('std::decay_t<decltype(*{})>'.format(c) for c in children) - return "using {} = Dune::PDELab::CompositeGridFunction<{}>;".format(name, templates) + if identifier == "is_dirichlet": + composite_type = "Dune::PDELab::CompositeConstraintsParameters" + else: + composite_type = "Dune::PDELab::CompositeGridFunction" + return "using {} = {}<{}>;".format(name, composite_type, templates) def type_composite_grid_function(identifier, children, root): if root: name = _grid_function_root_type(identifier) + elif identifier == "is_dirichlet": + name = "CompositeConstraintsParameters_{}".format('_'.join(c for c in children)) else: name = "CompositeGridFunction_{}".format('_'.join(c for c in children)) - typedef_composite_grid_function(name, children) + typedef_composite_grid_function(name, identifier, children) return name @@ -84,6 +106,11 @@ def define_composite_grid_function(identifier, name, children, root=True): return "{} = std::make_shared<{}>({});".format(name, composite_gfs_type, ', '.join('*{}'.format(c) for c in children)) +# +# Function used to generate grid function +# + + def function_lambda(func): assert isinstance(func, tuple) func = func[0] @@ -100,58 +127,92 @@ def function_lambda(func): @class_member(classtag="driver_block") -def typedef_function(name): - range_type = type_range() +def typedef_function(name, boolean=False): leafview_type = type_leafview() - entity = "typename {}::template Codim<0>::Entity".format(leafview_type) - coordinate = "typename {}::template Codim<0>::Entity::Geometry::LocalCoordinate".format(leafview_type) - return "using {} = std::function<{}({}, {})>;".format(name, range_type, entity, coordinate) + if boolean: + return_type = "bool" + entity = "typename {}::Intersection".format(leafview_type) + coordinate = "typename {}::Intersection::LocalCoordinate".format(leafview_type) + else: + return_type = type_range() + entity = "typename {}::template Codim<0>::Entity".format(leafview_type) + coordinate = "typename {}::template Codim<0>::Entity::Geometry::LocalCoordinate".format(leafview_type) + return "using {} = std::function<{}({}, {})>;".format(name, return_type, entity, coordinate) -def type_function(): - name = "FunctionExpression" - typedef_function(name) +def type_function(boolean): + if boolean: + name = "BoolFunctionExpression" + boolean = True + else: + name = "FunctionExpression" + boolean = False + typedef_function(name, boolean=boolean) return name @class_member(classtag="driver_block") -def declare_function(name): - function_type = type_function() +def declare_function(name, boolean): + function_type = type_function(boolean) return "std::shared_ptr<{}> {};".format(function_type, name) @preamble(section="vector", kernel="driver_block") -def define_function(name, func): - declare_function(name) - function_type = type_function() +def define_function(name, func, boolean): + declare_function(name, boolean) + function_type = type_function(boolean) fct_lambda = function_lambda(func) return "{} = std::make_shared<{}> ({});".format(name, function_type, fct_lambda) @cached -def name_function(func): +def name_function(func, boolean): name = get_counted_variable("functionExpression") - define_function(name, func) + define_function(name, func, boolean) return name +# +# Leaf grid function +# + + @class_member(classtag="driver_block") -def typedef_grid_function(name): +def typedef_grid_function(name, boolean=False): leafview_type = type_leafview() range_type = type_range() - function_type = type_function() - return "using {} = Dune::PDELab::LocalCallableToGridFunctionAdapter<{}, {}, {}, {}>;".format(name, - leafview_type, - range_type, - 1, - function_type) + function_type = type_function(boolean) + if boolean: + return "using {} = Dune::PDELab::LocalCallableToBoundaryConditionAdapter<{}>;".format(name, + function_type) + elif is_stationary: + return "using {} = Dune::PDELab::LocalCallableToGridFunctionAdapter<{}, {}, {}, {}>;".format(name, + leafview_type, + range_type, + 1, + function_type) + else: + from dune.codegen.pdelab.driver.gridoperator import type_localoperator + lop_type = type_localoperator(get_form_ident()) + return "using {} = Dune::PDELab::LocalCallableToInstationaryGridFunctionAdapter" \ + "<{}, {}, {}, {}>;".format(name, + leafview_type, + range_type, + 1, + function_type, + lop_type) def type_grid_function(identifier, root): - name = "GridFunctionLeaf" + if identifier == "is_dirichlet": + name = "BoolGridFunctionLeaf" + boolean = True + else: + name = "GridFunctionLeaf" + boolean = False if root: name = _grid_function_root_type(identifier) - typedef_grid_function(name) + typedef_grid_function(name, boolean=boolean) return name @@ -165,16 +226,23 @@ def declare_grid_function(identifier, name, root): def define_grid_function(identifier, name, func, root=True): declare_grid_function(identifier, name, root) gv = name_leafview() - function_name = name_function(func) + + if identifier == "is_dirichlet": + boolean = True + else: + boolean = False + function_name = name_function(func, boolean) + grid_function_type = type_grid_function(identifier, root) include_file('dune/pdelab/function/callableadapter.hh', filetag='driver') - if is_stationary(): + if identifier == "is_dirichlet": + return "{} = std::make_shared<{}>(*{});".format(name, grid_function_type, function_name) + elif is_stationary(): return "{} = std::make_shared<{}>({}, *{});".format(name, grid_function_type, gv, function_name) else: - # palpo TODO - assert False from dune.codegen.pdelab.driver.gridoperator import name_localoperator lop = name_localoperator(get_form_ident()) + return "{} = std::make_shared<{}>({}, *{}, *{});".format(name, grid_function_type, gv, function_name, lop) return "auto {} = Dune::PDELab::makeInstationaryGridFunctionFromCallable({}, {}, {});".format(name, gv, lambdaname, @@ -182,7 +250,6 @@ def define_grid_function(identifier, name, func, root=True): ) - def name_grid_function(identifier, element, func, root=True): assert isinstance(func, tuple) @@ -207,6 +274,11 @@ def name_grid_function(identifier, element, func, root=True): return name +# +# Name of root of grid function +# + + def name_grid_function_root(identifier): element = get_trial_element() func = preprocess_leaf_data(element, identifier) @@ -214,6 +286,11 @@ def name_grid_function_root(identifier): return name +# +# Use grid function outside the driver block +# + + @preamble(section="postprocessing", kernel="main") def main_typedef_grid_function(name, identifier, treepath): if len(treepath) == 0: @@ -259,7 +336,6 @@ def main_define_grid_function(name, identifier, treepath): return "auto {} = child(*{}, {});".format(name, root_name, ", ".join(i for i in indices)) - def main_name_grid_function(identifier, treepath): name = _grid_function_root_name(identifier) if len(treepath) > 0: