diff --git a/python/dune/codegen/blockstructured/__init__.py b/python/dune/codegen/blockstructured/__init__.py index 8810750ff4f0d1122429917c48f304b05d101667..dc9db5e5a7204099e6e8345a45dd5889de66f589 100644 --- a/python/dune/codegen/blockstructured/__init__.py +++ b/python/dune/codegen/blockstructured/__init__.py @@ -1,3 +1,4 @@ +import dune.codegen.blockstructured.accumulation import dune.codegen.blockstructured.quadrature import dune.codegen.blockstructured.argument import dune.codegen.blockstructured.geometry diff --git a/python/dune/codegen/blockstructured/basis.py b/python/dune/codegen/blockstructured/basis.py index 3477a18295fdae14a324a8c309635bb6df565537..e5aa4d20ebef0eb320fff559c2d2fb8b54fe909b 100644 --- a/python/dune/codegen/blockstructured/basis.py +++ b/python/dune/codegen/blockstructured/basis.py @@ -1,4 +1,5 @@ from dune.codegen.generation import (backend, + basis_mixin, kernel_cached, get_backend, instruction, @@ -9,7 +10,8 @@ from dune.codegen.generation import (backend, include_file,) from dune.codegen.tools import get_pymbolic_basename from dune.codegen.loopy.target import type_floatingpoint -from dune.codegen.pdelab.basis import (declare_cache_temporary, +from dune.codegen.pdelab.basis import (GenericBasisMixin, + declare_cache_temporary, name_localbasis_cache, type_localbasis, FEM_name_mangling) @@ -27,6 +29,56 @@ from ufl import MixedElement import pymbolic.primitives as prim +@basis_mixin("blockstructured") +class BlockStructuredBasisMixin(GenericBasisMixin): + def lfs_inames(self, element, restriction, number, context=""): + return lfs_inames(element, restriction, number, context=context) + + def implement_basis(self, element, restriction, number, context=''): + assert not isinstance(element, MixedElement) + name = "phi_{}".format(FEM_name_mangling(element)) + name = restricted_name(name, restriction) + self.evaluate_basis(element, name, restriction) + inames = self.lfs_inames(element, restriction, number, context=context) + + return prim.Subscript(prim.Variable(name), (tensor_index_to_sequential_index(inames, element.degree() + 1), 0)) + + @kernel_cached + def evaluate_basis(self, element, name, restriction): + temporary_variable(name, shape=((element.degree() + 1)**world_dimension(), 1), + decl_method=declare_cache_temporary(element, restriction, 'Function')) + cache = name_localbasis_cache(element) + qp = self.to_cell(self.quadrature_position()) + localbasis = name_localbasis(element) + instruction(inames=self.quadrature_inames(), + code='{} = {}.evaluateFunction({}, {});'.format(name, cache, str(qp), localbasis), + assignees=frozenset({name}), + read_variables=frozenset({get_pymbolic_basename(qp)}), + ) + + def implement_reference_gradient(self, element, restriction, number, context=''): + assert not isinstance(element, MixedElement) + name = "js_{}".format(FEM_name_mangling(element)) + name = restricted_name(name, restriction) + self.evaluate_reference_gradient(element, name, restriction) + inames = self.lfs_inames(element, restriction, number, context=context) + + return prim.Subscript(prim.Variable(name), (tensor_index_to_sequential_index(inames, element.degree() + 1), 0)) + + @kernel_cached + def evaluate_reference_gradient(self, element, name, restriction): + temporary_variable(name, shape=((element.degree() + 1)**world_dimension(), 1, world_dimension()), + decl_method=declare_cache_temporary(element, restriction, 'Jacobian')) + cache = name_localbasis_cache(element) + qp = self.to_cell(self.quadrature_position()) + localbasis = name_localbasis(element) + instruction(inames=self.quadrature_inames(), + code='{} = {}.evaluateJacobian({}, {});'.format(name, cache, str(qp), localbasis), + assignees=frozenset({name}), + read_variables=frozenset({get_pymbolic_basename(qp)}), + ) + + # define FE basis explicitly in localoperator @backend(interface="typedef_localbasis", name="blockstructured") @class_member(classtag="operator") @@ -68,49 +120,50 @@ def name_localbasis(leaf_element): return name -@kernel_cached -def evaluate_basis(leaf_element, name, restriction): - temporary_variable(name, shape=((leaf_element.degree() + 1)**world_dimension(), 1), - decl_method=declare_cache_temporary(leaf_element, restriction, 'Function')) - cache = name_localbasis_cache(leaf_element) - qp = pymbolic_quadrature_position_in_cell(restriction) - localbasis = name_localbasis(leaf_element) - instruction(inames=get_backend("quad_inames")(), - code='{} = {}.evaluateFunction({}, {});'.format(name, cache, str(qp), localbasis), - assignees=frozenset({name}), - read_variables=frozenset({get_pymbolic_basename(qp)}), - ) - - -def pymbolic_basis(leaf_element, restriction, number, context=''): - assert not isinstance(leaf_element, MixedElement) - name = "phi_{}".format(FEM_name_mangling(leaf_element)) - name = restricted_name(name, restriction) - evaluate_basis(leaf_element, name, restriction) - inames = lfs_inames(leaf_element, restriction, number, context=context) - - return prim.Subscript(prim.Variable(name), (tensor_index_to_sequential_index(inames, leaf_element.degree() + 1), 0)) - - -@kernel_cached -def evaluate_reference_gradient(leaf_element, name, restriction): - temporary_variable(name, shape=((leaf_element.degree() + 1)**world_dimension(), 1, world_dimension()), - decl_method=declare_cache_temporary(leaf_element, restriction, 'Jacobian')) - cache = name_localbasis_cache(leaf_element) - qp = pymbolic_quadrature_position_in_cell(restriction) - localbasis = name_localbasis(leaf_element) - instruction(inames=get_backend("quad_inames")(), - code='{} = {}.evaluateJacobian({}, {});'.format(name, cache, str(qp), localbasis), - assignees=frozenset({name}), - read_variables=frozenset({get_pymbolic_basename(qp)}), - ) - - -def pymbolic_reference_gradient(leaf_element, restriction, number, context=''): - assert not isinstance(leaf_element, MixedElement) - name = "js_{}".format(FEM_name_mangling(leaf_element)) - name = restricted_name(name, restriction) - evaluate_reference_gradient(leaf_element, name, restriction) - inames = lfs_inames(leaf_element, restriction, number, context=context) - - return prim.Subscript(prim.Variable(name), (tensor_index_to_sequential_index(inames, leaf_element.degree() + 1), 0)) +# @kernel_cached +# def evaluate_basis(leaf_element, name, restriction): +# temporary_variable(name, shape=((leaf_element.degree() + 1)**world_dimension(), 1), +# decl_method=declare_cache_temporary(leaf_element, restriction, 'Function')) +# cache = name_localbasis_cache(leaf_element) +# qp = pymbolic_quadrature_position_in_cell(restriction) +# localbasis = name_localbasis(leaf_element) +# instruction(inames=get_backend("quad_inames")(), +# code='{} = {}.evaluateFunction({}, {});'.format(name, cache, str(qp), localbasis), +# assignees=frozenset({name}), +# read_variables=frozenset({get_pymbolic_basename(qp)}), +# ) +# +# +# def pymbolic_basis(leaf_element, restriction, number, context=''): +# assert not isinstance(leaf_element, MixedElement) +# name = "phi_{}".format(FEM_name_mangling(leaf_element)) +# name = restricted_name(name, restriction) +# evaluate_basis(leaf_element, name, restriction) +# inames = lfs_inames(leaf_element, restriction, number, context=context) +# +# return prim.Subscript(prim.Variable(name), (tensor_index_to_sequential_index(inames, leaf_element.degree() + 1), 0)) + +# +# @kernel_cached +# def evaluate_reference_gradient(leaf_element, name, restriction): +# from pudb import set_trace; set_trace() +# temporary_variable(name, shape=((leaf_element.degree() + 1)**world_dimension(), 1, world_dimension()), +# decl_method=declare_cache_temporary(leaf_element, restriction, 'Jacobian')) +# cache = name_localbasis_cache(leaf_element) +# qp = pymbolic_quadrature_position_in_cell(restriction) +# localbasis = name_localbasis(leaf_element) +# instruction(inames=get_backend("quad_inames")(), +# code='{} = {}.evaluateJacobian({}, {});'.format(name, cache, str(qp), localbasis), +# assignees=frozenset({name}), +# read_variables=frozenset({get_pymbolic_basename(qp)}), +# ) +# +# +# def pymbolic_reference_gradient(leaf_element, restriction, number, context=''): +# assert not isinstance(leaf_element, MixedElement) +# name = "js_{}".format(FEM_name_mangling(leaf_element)) +# name = restricted_name(name, restriction) +# evaluate_reference_gradient(leaf_element, name, restriction) +# inames = lfs_inames(leaf_element, restriction, number, context=context) +# +# return prim.Subscript(prim.Variable(name), (tensor_index_to_sequential_index(inames, leaf_element.degree() + 1), 0)) diff --git a/python/dune/codegen/blockstructured/geometry.py b/python/dune/codegen/blockstructured/geometry.py index 4bc0e6131ccfd192f14cc6e2ab15f37b99a7841b..f19202ec8ed3a5b527302edab638d841b336663e 100644 --- a/python/dune/codegen/blockstructured/geometry.py +++ b/python/dune/codegen/blockstructured/geometry.py @@ -1,13 +1,17 @@ from dune.codegen.pdelab.restriction import restricted_name -from dune.codegen.generation import (get_backend, +from dune.codegen.generation import (geometry_mixin, + get_backend, temporary_variable, instruction, get_global_context_value) from dune.codegen.tools import get_pymbolic_basename from dune.codegen.options import (get_form_option, option_switch, get_option) -from dune.codegen.pdelab.geometry import (world_dimension, +from dune.codegen.pdelab.geometry import (AxiparallelGeometryMixin, + EquidistantGeometryMixin, + GenericPDELabGeometryMixin, + world_dimension, local_dimension, component_iname) from dune.codegen.blockstructured.tools import sub_element_inames @@ -15,6 +19,31 @@ import pymbolic.primitives as prim from loopy.match import Writes +@geometry_mixin("blockstructured_multilinear") +class BlockStructuredGeometryMixin(GenericPDELabGeometryMixin): + def facet_jacobian_determinant(self, o): + raise NotImplementedError("I think this case was never really implemented") + + def jacobian_inverse(self, o): + raise NotImplementedError("I have not yet ported this one") + + +@geometry_mixin("blockstructured_axiparallel") +class AxiparallelBlockStructuredGeometryMixin(AxiparallelGeometryMixin, BlockStructuredGeometryMixin): + def facet_jacobian_determinant(self, o): + return prim.Quotient(AxiparallelGeometryMixin.facet_jacobian_determinant(self, o), + prim.Power(get_form_option("number_of_blocks"), local_dimension())) + + def jacobian_inverse(self, o): + return prim.Quotient(AxiparallelGeometryMixin.facet_jacobian_determinant(self, o), + prim.Power(get_form_option("number_of_blocks"), local_dimension())) + + +@geometry_mixin("blockstructured_equidistant") +class EquidistantBlockStructuredGeometryMixin(EquidistantGeometryMixin, AxiparallelBlockStructuredGeometryMixin): + pass + + # TODO warum muss within_inames_is_final=True gesetzt werden? def compute_corner_diff(first, second, additional_terms=tuple()): corners = name_element_corners() @@ -258,23 +287,23 @@ def name_jacobian_inverse_transposed(restriction): define_jacobian_inverse_transposed(name) return name - -# scale Jacobian according to the order of the blockstructure -def pymbolic_jacobian_inverse(i, j, restriction): - if get_form_option("constant_transformation_matrix"): - from dune.codegen.pdelab.geometry import name_constant_jacobian_inverse_transposed - name_jit = name_constant_jacobian_inverse_transposed(restriction) - else: - name_jit = name_jacobian_inverse_transposed(restriction) - return prim.Product((get_form_option("number_of_blocks"), - prim.Subscript(prim.Variable(name_jit), (j, i)))) - - -# scale determinant according to the order of the blockstructure -def pymbolic_facet_jacobian_determinant(): - from dune.codegen.pdelab.geometry import name_facet_jacobian_determinant - return prim.Quotient(prim.Variable(name_facet_jacobian_determinant()), - prim.Power(get_form_option("number_of_blocks"), local_dimension())) +# +# # scale Jacobian according to the order of the blockstructure +# def pymbolic_jacobian_inverse(i, j, restriction): +# if get_form_option("constant_transformation_matrix"): +# from dune.codegen.pdelab.geometry import name_constant_jacobian_inverse_transposed +# name_jit = name_constant_jacobian_inverse_transposed(restriction) +# else: +# name_jit = name_jacobian_inverse_transposed(restriction) +# return prim.Product((get_form_option("number_of_blocks"), +# prim.Subscript(prim.Variable(name_jit), (j, i)))) +# +# +# # scale determinant according to the order of the blockstructure +# def pymbolic_facet_jacobian_determinant(): +# from dune.codegen.pdelab.geometry import name_facet_jacobian_determinant +# return prim.Quotient(prim.Variable(name_facet_jacobian_determinant()), +# prim.Power(get_form_option("number_of_blocks"), local_dimension())) # translate a point in the micro element into macro coordinates diff --git a/python/dune/codegen/blockstructured/quadrature.py b/python/dune/codegen/blockstructured/quadrature.py index 64282c687bc4d41a2b5c5fe28303cbc555a5ddae..d2875435fb72345a3bd87ee7e23983edbd9343fe 100644 --- a/python/dune/codegen/blockstructured/quadrature.py +++ b/python/dune/codegen/blockstructured/quadrature.py @@ -1,29 +1,30 @@ from dune.codegen.generation import (backend, quadrature_mixin, ) -from dune.codegen.pdelab.quadrature import (GenericQuadratureMixin, - quadrature_iname) +from dune.codegen.pdelab.quadrature import GenericQuadratureMixin from dune.codegen.blockstructured.geometry import name_point_in_macro import pymbolic.primitives as prim @quadrature_mixin("blockstructured") class BlockstructuredQuadratureMixin(GenericQuadratureMixin): - pass - - -@backend(interface="quad_pos", name='blockstructured') -def pymbolic_quadrature_position(): - quad_points = name_quadrature_points() - quad_iname = quadrature_iname() - - qp_in_micro = prim.Subscript(prim.Variable(quad_points), (prim.Variable(quad_iname),)) - - return prim.Variable(name_point_in_macro(qp_in_micro)) - - -@backend(interface="qp_in_cell", name="blockstructured") -def pymbolic_quadrature_position_in_cell(restriction): - from dune.codegen.pdelab.geometry import to_cell_coordinates - quad_pos = pymbolic_quadrature_position() - return to_cell_coordinates(quad_pos, restriction) + def quadrature_position(self): + original = GenericQuadratureMixin.quadrature_position(self) + return prim.Variable(name_point_in_macro(original)) + +# +# @backend(interface="quad_pos", name='blockstructured') +# def pymbolic_quadrature_position(): +# quad_points = name_quadrature_points() +# quad_iname = quadrature_iname() +# +# qp_in_micro = prim.Subscript(prim.Variable(quad_points), (prim.Variable(quad_iname),)) +# +# return prim.Variable(name_point_in_macro(qp_in_micro)) +# +# +# @backend(interface="qp_in_cell", name="blockstructured") +# def pymbolic_quadrature_position_in_cell(restriction): +# from dune.codegen.pdelab.geometry import to_cell_coordinates +# quad_pos = pymbolic_quadrature_position() +# return to_cell_coordinates(quad_pos, restriction) diff --git a/python/dune/codegen/options.py b/python/dune/codegen/options.py index 3e41ef98368ac2cf75517dec5824a4a3440ee6b0..83b57cf48b036302d0ff64e196ffe36062cfc0fa 100644 --- a/python/dune/codegen/options.py +++ b/python/dune/codegen/options.py @@ -184,6 +184,12 @@ def process_form_options(opt, form): accumulation_mixins="sumfact", ) + if opt.blockstructured: + opt = opt.copy(accumulation_mixins="blockstructured", + geometry_mixins="blockstructured", + quadrature_mixins="blockstructured", + ) + if opt.control: opt = opt.copy(accumulation_mixins="control") diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7f2fef85e537fbe264712de625dc4f4b61208ad8..4be79371bc51e40c4334f0e91343c522d00d2147 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -7,5 +7,5 @@ add_subdirectory(stokes) add_subdirectory(sumfact) add_subdirectory(coeffeval) -#add_subdirectory(blockstructured) +add_subdirectory(blockstructured) add_subdirectory(adjoint)