1from __future__ import absolute_import, division, print_function, unicode_literals
2__metaclass__ = type
3
4import hashlib
5import importlib
6
7import dune.grid.grid_generator
8
9from dune.generator import Constructor, Method
10from dune.generator.generator import SimpleGenerator
11
12generator = SimpleGenerator("GridView", "Dune::FemPy")
13
14def cppBool(value):
15    return "true" if value else "false"
16
17
18def load(includes, typeName, *args):
19    # includes = includes + ["dune/fempy/py/gridview.hh", "dune/fempy/py/grid/gridpart.hh"]
20    pyIncludes = ["dune/fempy/py/gridview.hh", "dune/fempy/py/grid/gridpart.hh"]
21    moduleName = "view_" + hashlib.md5(typeName.encode('utf-8')).hexdigest()
22    holder = "Dune::FemPy::GridPartPtr< " + typeName + " >"
23    # module = generator.load(includes, typeName, moduleName, *args, options=[holder])
24    module = generator.load([includes,pyIncludes], typeName, moduleName, *args)
25    dune.grid.grid_generator.addAttr(module, module.GridView)
26    return module
27
28
29def adaptiveLeafGridView(grid, *args, **kwargs):
30    """create an adaptive view of the leaf grid
31
32    Args:
33        grid:  grid to create the adaptive view for.
34               The grid must either be a hierarchical grid or a leaf view of one.
35
36    Returns:
37        GridView: the constructed grid view
38    """
39    if isinstance(grid, str):
40        import dune.create as create
41        grid = create.grid(grid,*args,**kwargs)
42    else:
43        assert args.__len__()==0 and kwargs.__len__()==0,\
44            "too many arguments passed to adaptiveLeafGridView method"
45
46    try:
47        grid = grid.hierarchicalGrid
48    except:
49        pass
50    gridModule = importlib.import_module(type(grid).__module__)
51
52    if not isinstance(grid, getattr(gridModule, "HierarchicalGrid")):
53        raise ValueError('Cannot only create an adaptiveLeafGridView from a DUNE grid.')
54
55    gridPartName = "Dune::Fem::AdaptiveLeafGridPart< " + grid._typeName + " >"
56    typeName = gridPartName + "::GridViewType"
57    includes = grid._includes + ["dune/fem/gridpart/adaptiveleafgridpart.hh", "dune/python/grid/gridview.hh", "dune/fempy/py/grid/gridpart.hh"]
58
59    # Note: AGP are constructed from the hierarchical grid like other grid
60    # views so the default ctor can be used
61    '''
62    constructor = Constructor([grid._typeName + " &grid","int"],
63                 ["std::cout << 'hallo\\n';",
64                  "Dune::FemPy::detail::addGridModificationListener( grid );",
65                  "return Dune::FemPy::constructGridPart<"+gridPartName+">( grid );"],
66                 ["pybind11::keep_alive< 1, 2 >()"])
67    '''
68    GridView = load(includes, typeName).GridView
69    # setattr(GridView,"canAdapt",True)
70    return GridView(grid)
71
72
73def filteredGridView(hostGridView, contains, domainId, useFilteredIndexSet=False):
74    """create a filtered grid view
75
76    Args:
77        hostGridView:        grid view to filter
78        contains:            function (Element -> int) returns a domain id for each element is contained in the resulting grid view
79        domainId:            contains==domainId used to define entities inside the filtered gv
80        useFilteredIndexSet: build index set containing only filtered entites? (defaults to false)
81
82    Returns:
83        GridView: the constructed grid view
84    """
85    includes = hostGridView._includes + ["dune/fem/gridpart/filteredgridpart.hh", "dune/fem/gridpart/filter/simple.hh", "dune/python/grid/gridview.hh", "dune/fempy/py/grid/gridpart.hh"]
86
87    hostGridViewType = hostGridView._typeName
88    hostGridPartType = "Dune::FemPy::GridPart< " + hostGridViewType + " >"
89    filterType = "Dune::Fem::SimpleFilter< " + hostGridPartType + " >"
90    gridPartName = "Dune::Fem::FilteredGridPart< " + hostGridPartType + ", " + filterType + ", " + cppBool(useFilteredIndexSet) + " >"
91    typeName = "Dune::Fem::FilteredGridPart< " + hostGridPartType + ", " + filterType + ", " + cppBool(useFilteredIndexSet) + " >::GridViewType"
92    constructor = Constructor(["pybind11::handle hostGridView", "pybind11::function contains", "int domainId"],
93                              ["auto containsCpp = [ contains ] ( const " + hostGridPartType + "::Codim< 0 >::EntityType &e ) {",
94                               "    return contains( e ).template cast< int >();",
95                               "  };",
96                               hostGridPartType + " &hostGridPart = Dune::FemPy::gridPart< " + hostGridViewType + " >( hostGridView );",
97                               "return Dune::FemPy::constructGridPart< " + gridPartName + " >( hostGridPart, " + filterType + "( hostGridPart, containsCpp, domainId ) );"],
98                              ["pybind11::keep_alive< 1, 2 >()"])
99    return load(includes,typeName,constructor).GridView(hostGridView, contains, domainId)
100
101
102def geometryGridView(coordFunction):
103    """convert a coordinate function into a grid view.
104
105    Args:
106        coordFunction:  coordinate function to convert
107
108    Returns:
109        GridView: the constructed grid view
110    """
111    assert not coordFunction._typeName.startswith("Dune::Python::SimpleGridFunction"),\
112"""at the moment the 'gridFunction' decorator does
113not work with the 'geometryGridView'.
114Interpolate into a discrete function space or use a
115'uflFunction' if the function can be written as a ufl expression.
116"""
117
118    includes = coordFunction._includes + ["dune/fem/gridpart/geometrygridpart.hh", "dune/python/grid/gridview.hh", "dune/fempy/py/grid/gridpart.hh"]
119    gridPartName = "Dune::Fem::GeometryGridPart< " + coordFunction._typeName + " >"
120    typeName = gridPartName + "::GridViewType"
121
122    constructor = Constructor([coordFunction._typeName + " &coordFunction"],
123                 ["return Dune::FemPy::constructGridPart<"+gridPartName+">( coordFunction );"],
124                 ["pybind11::keep_alive< 1, 2 >()"])
125    return load(includes, typeName, constructor).GridView(coordFunction)
126
127
128if __name__ == "__main__":
129    import doctest
130    doctest.testmod(optionflags=doctest.ELLIPSIS)
131