pax_global_header00006660000000000000000000000064131331442210014504gustar00rootroot0000000000000052 comment=16b8dad2359f1d2e90a76dbf5825ae2f5c69f248 dune-functions-2.5.1/000077500000000000000000000000001313314422100144525ustar00rootroot00000000000000dune-functions-2.5.1/.gitignore000066400000000000000000000007251313314422100164460ustar00rootroot00000000000000Makefile Makefile.in config.guess config.h.in config.log config.status config.h config.lt config.sub configure configure aclocal.m4 autom4te.cache depcomp install-sh missing mkinstalldirs libtool dune-functions.pc semantic.cache configure.lineno stamp-h1 dune-functions-*.tar.gz dune-functions-?.? ltmain.sh am .libs/ .deps/ *.la *.o *.lo test-driver dependencies.m4 dune.css build-cmake/ *~ compile CMakeFiles CMakeCache.txt language_tests/ DartConfiguration.tcl FC.h dune-functions-2.5.1/.gitlab-ci.yml000066400000000000000000000022461313314422100171120ustar00rootroot00000000000000--- variables: DUNECI_BRANCH: releases/2.5 before_script: - duneci-install-module https://gitlab.dune-project.org/core/dune-common.git - duneci-install-module https://gitlab.dune-project.org/core/dune-geometry.git - duneci-install-module https://gitlab.dune-project.org/core/dune-localfunctions.git - duneci-install-module https://gitlab.dune-project.org/staging/dune-uggrid.git - duneci-install-module https://gitlab.dune-project.org/core/dune-grid.git - duneci-install-module https://gitlab.dune-project.org/core/dune-istl.git - duneci-install-module https://gitlab.dune-project.org/staging/dune-typetree.git debian:9--gcc: image: duneci/base:9 script: duneci-standard-test debian:9--clang: image: duneci/base:9 script: duneci-standard-test --opts=/duneci/opts.clang allow_failure: true debian:8--gcc: image: duneci/base:8 script: duneci-standard-test debian:8-backports--clang: image: duneci/base:8-backports script: duneci-standard-test --opts=/duneci/opts.clang ubuntu:16.04--gcc: image: duneci/base:16.04 script: duneci-standard-test ubuntu:16.04--clang: image: duneci/base:16.04 script: duneci-standard-test --opts=/duneci/opts.clang dune-functions-2.5.1/CMakeLists.txt000066400000000000000000000014311313314422100172110ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8.6) project(dune-functions CXX) if(NOT (dune-common_DIR OR dune-common_ROOT OR "${CMAKE_PREFIX_PATH}" MATCHES ".*dune-common.*")) string(REPLACE ${CMAKE_PROJECT_NAME} dune-common dune-common_DIR ${PROJECT_BINARY_DIR}) endif() #find dune-common and set the module path find_package(dune-common REQUIRED) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules" ${dune-common_MODULE_PATH}) #include the dune macros include(DuneMacros) # start a dune project with information from dune.module dune_project() add_subdirectory("dune") add_subdirectory("doc") add_subdirectory("cmake/modules") add_subdirectory("examples") # finalize the dune project, e.g. generating config.h etc. finalize_dune_project(GENERATE_CONFIG_H_CMAKE) dune-functions-2.5.1/COPYING000066400000000000000000000041571313314422100155140ustar00rootroot00000000000000Copyright holders: 2016 Jakub Both 2016 Ansgar Burchardt 2013--2016 Christian Engwer 2015 Elisa Friebel 2013 Christoph Gersbacher 2013 Stefan Girke 2013--2016 Carsten Gräser 2015--2016 Felix Gruber 2015--2016 Christoph Grüninger 2016 Dominic Kempf 2015 Angela Klewinghaus 2013--2016 Steffen Müthing 2015--2016 Elias Pipping 2013--2016 Oliver Sander 2015 Jonathan Youett The dune-functions library, headers and test programs are copyrighted free software. You can use, modify and/or redistribute it under the terms of either one of the two following licenses: * The GNU Lesser General Public License as published by the Free Software Foundation, either Version 3 of the license or (at your option) any later version. You can find a copy of the GNU Lesser General Public License, Version 3, in the files GPL-3 and LGPL-3 or at . * Version 2 of the GNU General Public License as published by the Free Software Foundation, with the following special exception for linking and compiling against the dune-functions library, the so-called "runtime exception": As a special exception, you may use the dune-functions source files as part of a software library or application without restriction. Specifically, if other files instantiate templates or use macros or inline functions from one or more of the dune-functions source files, or you compile one or more of the dune-functions source files and link them with other files to produce an executable, this does not by itself cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. This license is intended to be similar to the GNU Lesser General Public License, Version 2, which by itself isn't suitable for a template library. You can find a copy of the GNU General Public License, Version 2, in the file GPL-2 or at . dune-functions-2.5.1/README000066400000000000000000000033161313314422100153350ustar00rootroot00000000000000Preparing the Sources ========================= Additional to the software mentioned in README you'll need the following programs installed on your system: cmake >= 2.8.6 Getting started --------------- If these preliminaries are met, you should run dunecontrol all which will find all installed dune modules as well as all dune modules (not installed) which sources reside in a subdirectory of the current directory. Note that if dune is not installed properly you will either have to add the directory where the dunecontrol script resides (probably ./dune-common/bin) to your path or specify the relative path of the script. On your project and all uninstalled DUNE source modules found the script will then call cmake. passing the required options for other dune-modules automatically. Most probably you'll have to provide additional information to dunecontrol (e. g. compilers, configure options) and/or make options. The most convenient way is to use options files in this case. The files defining four variables: CMAKE_FLAGS flags passed to cmake An example options file might look like this: #use this options to autogen, configure and make if no other options are given CMAKE_FLAGS=" \ -DCMAKE_CXX_COMPILER=g++-4.9 \ -DCMAKE_CXX_FLAGS='-Wall -pedantic' \ -DCMAKE_INSTALL_PREFIX=/install/path" #Force g++-4.9 and set compiler flags If you save this information into example.opts you can pass the opts file to dunecontrol via the --opts option, e. g. dunecontrol --opts=example.opts all More info --------- See dunecontrol --help for further options. The full build-system is described in the dune-common/doc/buildsystem (Git version) or under share/doc/dune-common/buildsystem if you installed DUNE!dune-functions-2.5.1/TODO.md000066400000000000000000000052121313314422100155410ustar00rootroot00000000000000# Open questions Feel free to put your wishes and questions into this file. It would be nice to prefix your statements with your initials or one more letter if needed. * OS: How do I specialize code for a particular basis? For example, how can I write an 'interpolate' method only for BSPlineBasis objects? * OS: Carsten has introduced various new names, for example 'pq' to refer to a PQkNodalBasis when constructing a composite basis. Can we find a sane naming scheme for them? ## Development ## Function space basis interface * OS: The TaylorHoodIndexSet class currently contains two members enum { multiIndexMaxSize = 2 }; size_type dimension() const; which were never officially discussed. Christian added them because something like this was needed, but we may want to discuss these methods at the next meeting. * Here is another point that needs future discussion: I just added the first implementation of a basis of a DG space. This one uses Lagrangian shape functions. I expect other DG spaces using other shape functions to appear eventually. Here is the issue: Currently, the LagrangeDGBasis has the shape function type hard-wired into the code. Any implementation for a DG space using a different set of shape functions will differ very little from it. Hence one may consider implementing a single DGBasis, and making the shape functions a template parameter. However, it is not clear what exactly this template parameter should be. It cannot be a LocalFiniteElement, because that would force us to pick a grid element type at compile time (you currently could not use the VirtualLocalFiniteElement here, because the code does not properly set it up). You cannot expect a factory here either, because then you cannot currently hard-wire the element type if that is what you want. I don't think this is a difficult issue, it just needs a bit of discussion. ## Function interface ### EntitySet interface * CaG: It seems that the EntitySet concept and GridViewEntitySet are candidates for dune-grid. ### GridFunction concept * CaG: Should GridFunction export the grid type? * CaG: If yes, should GridFunction store/export a pointer to the grid? * CaG: While LocalFunction is defined in a grid-agnostig way with local coordinates from a 'LocalContext'. In contrast to this the naming of GridFunction is linked to Grids: entitySet(), LocalContext=decltype(entitySet())::Element. There seems to be no need for this and we could simply rename this in a grid-agnostic way if someone comes up with better names than LocalizableFunction, localContextSet() dune-functions-2.5.1/cmake/000077500000000000000000000000001313314422100155325ustar00rootroot00000000000000dune-functions-2.5.1/cmake/modules/000077500000000000000000000000001313314422100172025ustar00rootroot00000000000000dune-functions-2.5.1/cmake/modules/CMakeLists.txt000066400000000000000000000001521313314422100217400ustar00rootroot00000000000000set(modules "DuneFunctionsMacros.cmake") install(FILES ${modules} DESTINATION ${DUNE_INSTALL_MODULEDIR}) dune-functions-2.5.1/cmake/modules/DuneFunctionsMacros.cmake000066400000000000000000000000501313314422100241300ustar00rootroot00000000000000# File for module specific CMake tests. dune-functions-2.5.1/config.h.cmake000066400000000000000000000025511313314422100171520ustar00rootroot00000000000000/* begin dune-functions put the definitions for config.h specific to your project here. Everything above will be overwritten */ /* begin private */ /* Name of package */ #define PACKAGE "@DUNE_MOD_NAME@" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "@DUNE_MAINTAINER@" /* Define to the full name of this package. */ #define PACKAGE_NAME "@DUNE_MOD_NAME@" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "@DUNE_MOD_NAME@ @DUNE_MOD_VERSION@" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "@DUNE_MOD_NAME@" /* Define to the home page for this package. */ #define PACKAGE_URL "@DUNE_MOD_URL@" /* Define to the version of this package. */ #define PACKAGE_VERSION "@DUNE_MOD_VERSION@" /* end private */ /* Define to the version of dune-functions */ #define DUNE_FUNCTIONS_VERSION "@DUNE_FUNCTIONS_VERSION@" /* Define to the major version of dune-functions */ #define DUNE_FUNCTIONS_VERSION_MAJOR @DUNE_FUNCTIONS_VERSION_MAJOR@ /* Define to the minor version of dune-functions */ #define DUNE_FUNCTIONS_VERSION_MINOR @DUNE_FUNCTIONS_VERSION_MINOR@ /* Define to the revision of dune-functions */ #define DUNE_FUNCTIONS_VERSION_REVISION @DUNE_FUNCTIONS_VERSION_REVISION@ /* end dune-functions Everything below here will be overwritten */ dune-functions-2.5.1/doc/000077500000000000000000000000001313314422100152175ustar00rootroot00000000000000dune-functions-2.5.1/doc/CMakeLists.txt000066400000000000000000000000671313314422100177620ustar00rootroot00000000000000add_subdirectory("doxygen") add_subdirectory("manual") dune-functions-2.5.1/doc/doxygen/000077500000000000000000000000001313314422100166745ustar00rootroot00000000000000dune-functions-2.5.1/doc/doxygen/.gitignore000066400000000000000000000001001313314422100206530ustar00rootroot00000000000000Doxyfile Doxyfile.in doxyerr.log doxygen.log doxygen-tag html dune-functions-2.5.1/doc/doxygen/CMakeLists.txt000066400000000000000000000001121313314422100214260ustar00rootroot00000000000000# shortcut for creating the Doxyfile.in and Doxyfile add_doxygen_target() dune-functions-2.5.1/doc/doxygen/Doxylocal000066400000000000000000000025601313314422100205600ustar00rootroot00000000000000# This file contains local changes to the doxygen configuration # please us '+=' to add file/directories to the lists # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT += @top_srcdir@/dune/functions \ @top_srcdir@/TODO.md \ @top_srcdir@/doc/doxygen/mainpage.md \ @top_srcdir@/dune/functions/modules.md USE_MDFILE_AS_MAINPAGE = @top_srcdir@/doc/doxygen/mainpage.md # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # EXCLUDE += @top_srcdir@/dune/functions/test # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). # EXAMPLE_PATH += @top_srcdir@/src # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). # IMAGE_PATH += @top_srcdir@/dune/functions/pics dune-functions-2.5.1/doc/doxygen/mainpage.md000066400000000000000000000052031313314422100207770ustar00rootroot00000000000000 # The Dune-Function module The dune-functions module provides an abstraction layer for global finite element functions. Its two main concepts are functions implemented as callable objects, and bases of finite element spaces. ## Functions dune-functions provides an interface to "functions" in the mathematical sense, in particular to finite element functions defined on a grid, but going far beyond that. The interface revolves around the concept of a "callable". It encompasses any type of C++ object that can be evaluated with operator(), like free functions, function objects, and even C++11 lambdas. Dynamic polymorphism is realized using type erasure and the std::function class, which does not sacrifice efficiency in purely static code. dune-functions extends the "callable" concept into several directions. First, it allows for differentiable functions. Such functions can hand out their derivative as new function objects. Second, for functions defined piecewisely on a finite element grid, the concept of local function is introduced. Local functions can be bound to grid elements. All further evaluations of a function bound to an element are in local coordinates of that element. This approach allows to avoid overhead when there are many evaluations on a single element. For more details refer to the @ref Functions section. ## Function space bases The second part of dune-functions provides a well-defined interface to bases of finite element function spaces. For this interface, a finite element basis is a set of functions with a prescribed ordering, and a way to index them. The core functionality has three parts: 1. For a given grid element, obtain the restrictions of all basis functions to this element, except for those functions where the restriction is zero. In other words: get the shape functions for the element. 2. Get a local numbering for these shape functions. This is needed to index the element stiffness matrix. 3. Get a global numbering for the shape functions. This is needed to index the global stiffness matrix. While local numbers are always integers, global numbers can be multi-indices, if appropriate. A central feature is that finite element bases for vector-valued and mixed spaced can be constructed by tensor multiplication of simpler bases. The resulting expressions can be interpreted as tree structures. For example, the tree for the three-dimensional Taylor-Hood basis is shown above. This tree structure is directly exposed in the dune-functions interface. An easy mechanism allows to construct new spaces. For more details refer to the @ref FunctionSpaceBases section. dune-functions-2.5.1/doc/manual/000077500000000000000000000000001313314422100164745ustar00rootroot00000000000000dune-functions-2.5.1/doc/manual/.gitignore000066400000000000000000000001131313314422100204570ustar00rootroot00000000000000*.atfi *.aux *.bbl *.blg *.log *.out *.tdo *.toc dune-functions-manual.pdfdune-functions-2.5.1/doc/manual/CMakeLists.txt000066400000000000000000000004401313314422100212320ustar00rootroot00000000000000set(SOURCES ../../examples/stokes-taylorhood.cc ) set(IMAGES gfx/driven_cavity.pdf gfx/driven_cavity_result.png gfx/taylor_hood_tree.pdf ) if(LATEX_USABLE) dune_add_latex_document(dune-functions-manual.tex INPUTS ${SOURCES} IMAGES ${IMAGES}) endif(LATEX_USABLE) dune-functions-2.5.1/doc/manual/dune-functions-manual.bib000066400000000000000000000001721313314422100233660ustar00rootroot00000000000000@Book{braess:2013, author = {Dietrich Braess}, title = {Finite Elemente}, publisher = {Springer Verlag}, year = {2013} } dune-functions-2.5.1/doc/manual/dune-functions-manual.tex000066400000000000000000001346201313314422100234400ustar00rootroot00000000000000\documentclass[a4paper,10pt,headings=normal,bibliography=totoc]{scrartcl} \usepackage{scrhack} % Fix a LaTeX warning %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \usepackage[utf8x]{inputenc} \usepackage{amsmath} \usepackage{amssymb} \usepackage{amsthm} \usepackage{bm} \usepackage{colonequals} \usepackage{overpic} \usepackage{url} \usepackage{xspace} \usepackage[square,numbers,sort]{natbib} %\usepackage[colorinlistoftodos]{todonotes} \usepackage[colorinlistoftodos,disable]{todonotes} \usepackage{environ} \usepackage{enumitem} \usepackage{listings} \usepackage{float} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%% hyperref should be loaded late to avoid incompatibilities \usepackage[pdftitle={The dune-functions module}, pdfauthor={Oliver Sander}] {hyperref} \usepackage{attachfile2} \usepackage{fancyvrb} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%% Settings for the listings package \lstset{language={c++}, basicstyle=\ttfamily\small, % basicstyle=\small, commentstyle=\textit, % columns=fixed, columns=flexible, escapeinside={/*@}{@*/} } % How to include ranges of an external source code file \lstset{rangeprefix=//\ \{\ ,% curly left brace plus space, all in a C++-style comment rangesuffix=\ \},% space plus curly right brace numberstyle=\footnotesize, % font size for numbers includerangemarker=false} % Do not show the range markers \newcommand{\cpp}[1]{\lstinline[basicstyle=\ttfamily]!#1!} %%%%%%%%%%%%%% Define a 'shellenv' environment for shell output \usepackage{fancyvrb} \DefineVerbatimEnvironment% {shellenv}{Verbatim} {} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newcommand{\R}{\mathbb{R}} \newcommand{\abs}[1]{{\lvert#1\rvert}} \newcommand{\norm}[1]{\lVert#1\rVert} \renewcommand{\div}{\operatorname{div}} \DeclareMathOperator{\trace}{tr} \newcommand{\dune}{\textsc{Dune}\xspace} \newcommand{\program}[1]{\textsc{#1}\xspace} % For typesetting Dune module names \newcommand{\dunemodule}[1]{\texttt{#1}} % For typesetting file names \newcommand{\file}[1]{\texttt{#1}} %% All graphics files must be in this subdirectory \graphicspath{{gfx/}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \title{The dune-functions module} \author{Oliver Sander} %\date{} \begin{document} \maketitle \begin{abstract} \dunemodule{dune-functions} is a \dune module that provides interfaces for functions and function space bases. It forms one abstraction level above grids, shape functions, and linear algebra, but still sits below full discretization frameworks like \dunemodule{dune-pdelab} and \dunemodule{dune-fem}. As an example, this document shows how the \dunemodule{dune-functions} module can be used to solve the Stokes equation with a Taylor--Hood discretization. \end{abstract} \section{Solving the Stokes equation with \dunemodule{dune-functions}} \subsection{The Stokes equation} \begin{figure} \begin{center} \includegraphics[height=0.3\textheight]{driven_cavity} \qquad \includegraphics[height=0.3\textheight]{driven_cavity_result} \end{center} \caption{Driven cavity. Left: setting, right: simulation result. The arrows show the {\em normalized} velocity.} \label{fig:dune_functions:driven_cavity} \end{figure} The Stokes equation models a viscous incompressible fluid in a $d$-dimensional domain $\Omega$. There are two unknowns in this problem: a stationary fluid velocity field $\mathbf{u} : \Omega \to \R^d$, and the fluid pressure $p : \Omega \to \R$. Together, they have to solve the boundary value problem \begin{alignat*}{2} -\Delta \mathbf{u} - \nabla p & = 0 & \qquad & \text{in $\Omega$} \\ \div \mathbf{u} & = 0 & & \text{in $\Omega$} \\ \mathbf{u} & = \mathbf{u}_D & & \text{on $\partial \Omega$}, \end{alignat*} where we have omitted the physical parameters. The boundary value problem only determines the pressure $p$ up to a constant function. The pressure is therefore usually normalized such that $\int_\Omega p\,dx = 0$. Due to the constraint $\div \mathbf{u} = 0$, the corresponding weak form of the equation is a saddle-point problem. Introduce the spaces \begin{align*} \mathbf{H}^1_D(\Omega) & \colonequals \big\{ \mathbf{v} \in \mathbf{H}^1(\Omega) \; :\; \operatorname{tr}{\mathbf{v}} = \mathbf{u}_D \big\}, \\ L_{2,0}(\Omega) & \colonequals \Big\{ q \in L_2(\Omega) \; :\; \int_\Omega q\,dx = 0 \Big\}, \end{align*} and the bilinear forms \begin{equation*} a(\mathbf{u},\mathbf{v}) \colonequals \int_\Omega \nabla \mathbf{u} \nabla \mathbf{v} \,dx, \qquad \text{and} \qquad b(\mathbf{v},q) \colonequals \int_\Omega \div \mathbf{v} \cdot q \,dx. \end{equation*} Then the weak form of the Stokes equation is: Find $(\mathbf{u},p) \in \mathbf{H}_D^1(\Omega) \times L_{2,0}(\Omega)$ such that \begin{alignat*}{2} a(\mathbf{u},\mathbf{v}) + b(\mathbf{v},p) & = 0 & \qquad & \text{for all $\mathbf{v} \in \mathbf{H}_0^1(\Omega)$} \\ b(\mathbf{u},q)\qquad\qquad & = 0 & & \text{for all $q \in L_{2,0}(\Omega)$}. \end{alignat*} If $\mathbf{u}_D$ is sufficiently smooth, this variational problem has a unique solution. The Taylor--Hood element is the standard way to discretize this saddle point problem~\cite{braess:2013}. \subsection{The driven-cavity benchmark} For our example we choose to simulate a two-dimensional driven cavity. This is a standard benchmark for the Stokes problem in the literature. Let $\Omega$ be the unit square $[0,1]^2$, and set the Dirichlet boundary conditions for the velocity $\mathbf{u}$ to \begin{equation*} \mathbf{u}(x) = \begin{cases} (0,1) & \text{if $x \in \{0\} \times [0,1]$} \\ (0,0) & \text{elsewhere on $\partial \Omega$}. \end{cases} \end{equation*} The interpretation of this is a fluid container that is closed on all but one side. While the fluid remains motionless on the closed sides, an external agent drives a constant upward motion on the left vertical side. The domain and boundary conditions are depicted in Figure~\ref{fig:dune_functions:driven_cavity}, left. The corresponding solution is shown on the right side of the same figure. The velocity forms a vortex, while the pressure forms extrema in the two left corners. In the following discussion we always use the letter $d$ to denote the space dimension, even though it is known to be $d=2$ for our specific example. This is to avoid confusion, because the number~2 also appears a few times because we have two types of unknowns. \subsection{Discretization} \begin{figure} \begin{center} \begin{overpic}[width=0.5\textwidth]{taylor_hood_tree} \put(5,5){$P_2$} \put(30,5){$P_2$} \put(55,5){$P_2$} \put(87,31){$P_1$} \put(5,30){$V_\text{v}$} \put(5,57){$B_\text{TH}$} \put(30.7,32){$\otimes$} \put(61.6,58){$\otimes$} \end{overpic} \end{center} \caption{Taylor--Hood basis $P_2 \otimes P_2 \otimes P_2 \otimes P_1$ in a tree representation} \label{fig:taylor_hood_basis_tree} \end{figure} We discretize the domain using a structured axis-aligned grid with $4 \times 4$ uniform quadrilateral elements. On this grid, we use the Taylor--Hood element to discretize the weak saddle-point problem. The nodal basis of the Taylor--Hood element has a natural tree structure as shown in Figure~\ref{fig:taylor_hood_basis_tree}. On each element, the \dunemodule{dune-functions} implementation provides a local numbering of all shape functions on this element. This numbering uses a simple integer as index type, and is used to address the entries of the element stiffness matrix. \begin{table} \begin{center} \begin{tabular}{c|c} basis function & multi-index \\ \hline \\ $b_{x,0}$ & $(0,0)$ \\ $b_{y,0}$ & $(0,1)$ \\ $b_{z,0}$ & $(0,2)$ \\ $b_{x,1}$ & $(0,3)$ \\ $b_{y,1}$ & $(0,4)$ \\ $b_{z,1}$ & $(0,5)$ \\ $b_{x,2}$ & $(0,6)$ \\ $b_{y,2}$ & $(0,7)$ \\ $b_{z,2}$ & $(0,8)$ \\ \vdots & \vdots \\ $p_0$ & $(1,0)$ \\ $p_1$ & $(1,1)$ \\ $p_2$ & $(1,2)$ \\ \vdots & \vdots \end{tabular} \end{center} \caption{Multi-index for the Taylor--Hood basis with interleaved ordering of the velocity basis functions} \label{tbl:th_multiindices_interleaved} \end{table} Each global basis function additionally gets a global index, used to address the entries of the global stiffness matrix. In principle, \dunemodule{dune-functions} provides several types of orderings and multi-indices here. The one that is used in the code example is given in Table~\ref{tbl:th_multiindices_interleaved}: Each global index is a pair $(a,b)$, where $a \in \{0,1\}$ switches between velocity and pressure basis functions, and $b \in \mathbb{N}$ selects a particular basis function in either the set of velocity basis functions or the set of pressure basis functions. \subsection{Implementation} This chapter discusses an example implementation of the Stokes problem, using only \dunemodule{dune-functions} and no higher-level modules. The example is contained in a single file, which comes as part of the \dunemodule{dune-functions} source tree, in \file{dune-functions/examples/stokes-taylorhood.cc}. If you read this document in electronic form, the file can also be accessed by clicking on the icon in the margin.% % \marginpar{\attachfile[author=The dune-functions team, color = 1 0 0, mimetype=text/plain, description=Complete source code of the Stokes/Taylor-Hood example] {../../examples/stokes-taylorhood.cc}} \subsubsection{The \texorpdfstring{\cpp{main}}{main} method} We begin discussing the example code by describing its \cpp{main} method. This method begins by setting up MPI and the grid. We pick \cpp{YaspGrid} for the structured $4 \times 4$ quadrilateral grid. Note that there is the line % \lstinputlisting[linerange={using_namespace_dune_begin-using_namespace_dune_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % at the top of the file, so this namespace is imported completely. Additionally, everything in the \dunemodule{dune-functions} module is in the namespace \cpp{Functions}. This namespace is not imported; instead, the prefix \cpp{Functions::} is always given explicitly. % \lstinputlisting[linerange={main_begin-grid_setup_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % The \cpp{gridView} object is the flat finite element grid that we will use for the computation. On this grid view, we then set up the function space basis for the Taylor--Hood element. This is as simple as % \lstinputlisting[linerange={function_space_basis_begin-function_space_basis_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % For each element, the \cpp{taylorHoodBasis} object will give us the tree of shape functions, and the corresponding local and global numberings. Before being able to assemble the stiffness matrix of the Stokes system we need to pick suitable data structures for the linear algebra. The implementation of the Taylor--Hood basis selected in Line~\ref{li:stokes_taylorhood_select_taylorhoodbasis} orders the velocity degrees of freedom before the pressure degrees of freedom. Further, the velocity components are interleaved. The indexing scheme results from grouping degrees of freedom at the tree root. The resulting multi-indices all have length~2, and are given in Table~\ref{tbl:th_multiindices_interleaved}. Consequently, the appropriate vector type is a pair of scalar vectors, one for the velocity and one for the pressure degrees of freedom. Analogously, the matrix must consist of $2 \times 2$ large sparse scalar matrices. The following code sets up vector and matrix types for this, using the nesting machinery from \dunemodule{dune-istl}. % \lstinputlisting[linerange={linear_algebra_setup_begin-linear_algebra_setup_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % Other index types are possible and possibly desirable here. These would correspond to other vector and matrix data types. Now that we have chosen the C++ types for the matrix and vector data structures we can actually assemble the system. Assembling the right-hand-side vector \cpp{rhs} is easy, because, apart from the Dirichlet boundary data (which we will insert later), all its entries are zero. An all-zero vector of the correct type and size is set up by the following lines % \lstinputlisting[linerange={rhs_assembly_begin-rhs_assembly_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % The \cpp{HierarchicVectorView} is a device that offers easier handling of arbitrarily nested vector data types. In particular, it offers convenient resizing of an entire hierarchy of nested vectors. The \cpp{taylorHoodBasis} object informs about the sizes of the corresponding finite element basis subtrees, and Line~\ref{li:stokes_taylorhood_set_rhs_to_zero} fills the entire vector with zeros. To obtain the stiffness matrix we first create an empty matrix object of the correct type. The actual assembly is factored out into a separate method. % \lstinputlisting[linerange={matrix_assembly_begin-matrix_assembly_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % As the matrix assembly is the central part of this example we explain it in detail below, after having covered the \cpp{main} method. Suppose now that we have the correct stiffness matrix assembled in the object \cpp{stiffnessMatrix}. We still need to modify the linear system to include the Dirichlet information. In a first step we need to determine all degrees of freedom with Dirichlet data. These are all the velocity degrees of freedom on the domain boundary. We could do this by using the \cpp{LocalKey} object of each basis function to single out all those that are assigned to a boundary entity. However, on a simple domain as the unit square used here it is easier to use a geometric criterion. We first define a predicate that returns \cpp{true} if a given global coordinate \cpp{x} is on the domain boundary: % \lstinputlisting[linerange={boundary_predicate_begin-boundary_predicate_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % The we interpolate this boolean-valued function in the space spanned by the velocity basis functions. % \lstinputlisting[linerange={interpolate_boundary_predicate_begin-interpolate_boundary_predicate_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % Observe how the \dunemodule{dune-functions} interface allows to interpolate C++11 lambdas, which makes the code very short and readable. The expression \cpp{TypeTree::hybridTreePath(_0,i)} selects the different coordinate directions of the velocity basis from the tree representation given in Figure~\ref{fig:taylor_hood_basis_tree}. As the bases for the velocity components are all the same, an ordinary integer \cpp{i} is sufficient to choose one of them. In contrast, the velocity and pressure bases are different C++ types, and a compile-time construction is needed to choose between them. The object \cpp{_0} is defined in \file{dune/typetree/utility.hh} as (roughly) \begin{lstlisting} std::integer_constant _0; \end{lstlisting} In the \cpp{TaylorHoodBasis} implementation, \cpp{_0} selects the velocity subtree and \cpp{_1} selects the pressure subtree. Finally, we define a function implementing the actual Dirichlet values function $\mathbf{u}_D$, and interpolate that into the right-hand-side vector \cpp{rhs}. % \lstinputlisting[linerange={interpolate_dirichlet_values_begin-interpolate_dirichlet_values_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % The expression \cpp{TypeTree::hybridTreePath(_0)} demands that only velocity degrees of freedom are interpolated. The \cpp{isBoundary} vector given as the last argument restricts the interpolation to only the boundary degrees of freedom. The stiffness matrix is modified in a more manual fashion. For each Dirichlet degree of freedom we need to fill the corresponding matrix row with zeros, and write a~1 on the diagonal. As only velocity degrees of freedom have Dirichlet values, we need to modify the two upper matrix blocks only. % \lstinputlisting[linerange={set_dirichlet_matrix_begin-set_dirichlet_matrix_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % Finally, we can solve the linear system. Efficiently solving the Stokes system is an art, which we do not want to get into here. Instead, we a GMRes solver, without any preconditioner at all. This is known to converge, albeit slowly. \todo[inline]{Eigentlich peinlich. Können wir nicht doch einen vernünftigen Löser nehmen?} The advantage is that it can be written down in very few lines. % \lstinputlisting[linerange={stokes_solve_begin-stokes_solve_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % Observe how the \cpp{RestartedGMResSolver} object is completely oblivious to the fact that the matrix has a two-level nesting structure. On the other hand, dedicated Stokes solvers usually operate on some sort of Schur complement, and hence they need direct access to the four submatrices. This can be elegantly done using the nested matrix type used for the stiffness matrix. Once the iterative solver has terminated, we write the result to a VTK file. For this, we write the resulting velocity as a vector field, and the resulting pressure as a scalar field. We subsample the grid twice, because the \cpp{VTKWriter} class natively only displays piecewise linear functions. % \lstinputlisting[linerange={stokes_output_begin-stokes_output_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % When run, this program produces a file called \file{function-stokes-result.vtu}. The file can be opened in \program{ParaView}, and the outcome looks like the image on the right in Figure~\ref{fig:dune_functions:driven_cavity}. \subsubsection{The global assembler} Now that we have covered the \cpp{main} method, we can turn to the assembler for the Stokes stiffness matrix. As our main focus is the use of the \dunemodule{dune-functions} interfaces, the assembler is the central part of our example. We begin with the global assembler, which is the routine \cpp{assembleStokesMatrix} called in Line~\ref{li:stokes_taylorhood_call_to_assemblestokesmatrix} of the \cpp{main} method. The global assembler sets up the matrix pattern, loops over all elements, and accumulates the element stiffness matrices in the global matrix. The signature of the method is % \lstinputlisting[linerange={global_assembler_signature_begin-global_assembler_signature_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % The only arguments it gets are the finite element basis and the matrix to fill. Observe that the Taylor--Hood basis is not hard-wired here, so we could call the method with a different basis. However, not surprisingly the assembler for the Stokes problem makes relatively tight assumptions on the basis tree structure, so relatively little practical freedom is possible here. Ideally, a global assembler should be fully generic, and all knowledge about the current spaces and differential operators should be confined to the local assembler. Real discretization frameworks like \dunemodule{dune-pdelab} do achieve this separation, but for our example here we are less strict, to avoid technicalities. The first few lines of the \cpp{assembleStokesMatrix} method set up the matrix occupation pattern, and initialize the matrix with zeros. % \lstinputlisting[linerange={setup_matrix_pattern_begin-setup_matrix_pattern_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % The actual pattern assembly is implemented in a separate method \cpp{getOccupationPattern}. It returns a $2 \times 2$ table of \cpp{MatrixIndexSet} objects. \todo[inline]{Erklären? Überspringen? Anders implementieren?} The four \cpp{BCRSMatrix} objects are initialized with these patterns in Line~\ref{li:stokes_taylorhood_setup_matrix_patterns}. Line~\ref{li:stokes_taylorhood_set_matrix_to_zero} fills the entire matrix with zeros. Next comes the actual element loop. We first request a \cpp{localView} object and a \cpp{localIndexSet} object from the finite element basis: % \lstinputlisting[linerange={get_localview_begin-get_localview_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % After that, we start the loop over the grid elements. For each element, we bind the \cpp{localView} object to the element and the \cpp{localIndexSet} object to the \cpp{localView}. From now on all enquiries to the local view and index set will implicitly refer to this element. % \lstinputlisting[linerange={element_loop_and_bind_begin-element_loop_and_bind_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % We then create the element stiffness matrix, and call the separate method \cpp{getLocalMatrix} to fill. By default, \dunemodule{dune-functions} supposes that the element stiffness matrix is dense and non-hierarchical, and Line~\ref{li:stokes_taylorhood_select_element_matrix_type} picks a suitable type for such a matrix. % \lstinputlisting[linerange={setup_element_stiffness_begin-setup_element_stiffness_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % The \cpp{getLocalMatrix} method is discussed in detail below. In addition to the \cpp{elementMatrix} object, it gets only the \cpp{localView} object. This object contains all necessary information. Finally, we loop over the entries of the element stiffness matrix and add them onto the global matrix. % \lstinputlisting[linerange={accumulate_global_matrix_begin-accumulate_global_matrix_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % The type returned in Lines~\ref{li:stokes_taylorhood_get_global_row_index} and~\ref{li:stokes_taylorhood_get_global_column_index} for the global row and column indices is a multi-index. It has length~2 for both velocity degrees of freedom and for pressure degrees of freedom. Observe how Line~\ref{li:stokes_taylorhood_scatter_matrix_indices} uses the length-2 multi-index to access the nested matrix type. For vectors, this scattering of multi-indices is implemented in general form in the \cpp{HierarchicVectorWrapper} class. The preceding loops write in particular into the lower right matrix block, even though we know that for the Stokes system this block contains only zeros. A more optimized version of the code would leave out the lower right submatrix altogether. \subsubsection{The local assembler} Finally, we investigate the method that assembles the element stiffness matrices. Its signature is % \lstinputlisting[linerange={local_assembler_signature_begin-local_assembler_signature_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % As you see, it only receives the local view of the Taylor--Hood basis, expected to be bound to an element, and the empty matrix. The first few lines of the method gather some information about the element the method is to work on. In particular, from the \cpp{localView} object it extracts the element itself, and the element's dimension and geometry % \lstinputlisting[linerange={local_assembler_get_element_information_begin-local_assembler_get_element_information_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % Next, the element stiffness matrix is initialized. The \cpp{localView} object knows the total number of degrees of freedom of the element it is bound to, and since the matrix is scalar this is the correct number of matrix rows and columns. % \lstinputlisting[linerange={initialize_element_matrix_begin-initialize_element_matrix_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % Finally, we first ask for the set of velocity and pressure shape functions. % \lstinputlisting[linerange={get_local_fe_begin-get_local_fe_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % The two objects are \cpp{LocalFiniteElement}s in the \dunemodule{dune-localfunctions} sense of the word. In fact, they are objects of the \cpp{LocalFiniteElementVirtualInterface} class. The virtual interface of \dunemodule{dune-localfunctions} is used here because the Taylor--Hood basis implementation accommodates grids with more than a single element type. In Lines~\ref{li:stokes_taylorhood_get_velocity_lfe}--\ref{li:stokes_taylorhood_get_pressure_lfe} you see the tree structure of the Taylor--Hood basis in action again: The expression \begin{lstlisting} localView.tree().child(_0,0) \end{lstlisting} returns the first child of the first child of the root, i.e., the basis for the $x_0$-component of the velocity field, and \begin{lstlisting} localView.tree().child(_1) \end{lstlisting} is the basis for the pressure space. As the root of the tree combines two different bases, we need to use the static identifiers \cpp{_0} and \cpp{_1} from the \cpp{Dune::TypeTree::Indices} namespace to specify its children. The inner node for the velocities combines $d$ times the same basis, and hence the normal integer \cpp{0} can be used to address its first child. Our implementation of the local Stokes assembler is actually ``cheating'', because it exploits the knowledge that the same basis is used for all velocity components. Therefore, only the first leaf of the velocity subtree is acquired in Line~\ref{li:stokes_taylorhood_get_velocity_lfe}, and then used for all components. Using separate local finite elements is wasteful because the same shape function values and gradients would be computed multiple times. Next, we construct a suitable quadrature rule and loop over the quadrature points. The formula for the quadrature order combines information about the element type, the shape functions, and the differential operator. \todo[inline]{\cpp{QuadratureRuleKey} verwenden!} % \lstinputlisting[linerange={begin_quad_loop_begin-begin_quad_loop_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % The quadrature loop starts like similar local assembler codes seen elsewhere. First, we get the inverse transposed Jacobian of the map from the reference element to the grid element, and the Jacobian determinant for the integral transformation formula % \lstinputlisting[linerange={quad_loop_preamble_begin-quad_loop_preamble_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % With these preparations done, we can assemble the first part of the stiffness matrix, corresponding to the velocity--velocity coupling. For two $d$-valued velocity basis functions $\bm{\varphi}_i^k = \mathbf{e}_k \varphi_i$ and $\bm{\varphi}_j^l = \mathbf{e}_l \varphi_j$ we need to compute \begin{equation*} a(\bm{\varphi}_i^k, \bm{\varphi}_j^l) = \int_\Omega \nabla \bm{\varphi}_i^k \nabla \bm{\varphi}_j^l \,dx = \delta_{kl} \int_\Omega \nabla \varphi_i \nabla \varphi_j \,dx, \end{equation*} where $\varphi_i$ and $\varphi_j$ are the corresponding scalar basis functions. The code first computes the derivatives of the velocity shape functions at the current quadrature point, and then uses the matrix in \cpp{jacobian} to transform the shape functions gradients to gradients of the actual basis functions defined on the grid element. % \lstinputlisting[linerange={velocity_gradients_begin-velocity_gradients_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % Withe the velocity basis function gradients at hand we can assemble the velocity contribution to the stiffness matrix. % \lstinputlisting[linerange={velocity_velocity_coupling_begin-velocity_velocity_coupling_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % Noteworthy here are the Lines~\ref{li:stokes_taylorhood_compute_vv_element_matrix_row}--\ref{li:stokes_taylorhood_compute_vv_element_matrix_column} which, for two given shape functions from the finite element basis tree, compute the flat lexicographic numbering used to index the element stiffness matrix. The expression \cpp{child(_0,k)} singles out the tree leaf for the \cpp{k}-th component of the velocity basis. The loop variables \cpp{i} and \cpp{j} run over the shape functions in this set, and \begin{lstlisting} localView.tree().child(_0,k).localIndex(i); \end{lstlisting} returns the corresponding scalar index for this shape function in the set of {\em all} shape functions of the Taylor--Hood basis on this element. Line~\ref{li:stokes_taylorhood_update_vv_element_matrix} then updates the corresponding (scalar) element matrix entry with the correctly weighted product the two gradients $\nabla \varphi_i$ and $\nabla \varphi_j$. Once this part is understood, computing, the velocity--pressure coupling terms is easy. For a given velocity shape function $\bm{\varphi}_i^k$ and pressure shape function $\theta_j$ we need to compute \begin{equation*} b(\bm{\varphi}_i^k,\theta_j) = \int_\Omega \operatorname{div} \bm{\varphi}_i^k \cdot \theta_j\,dx = \int_\Omega \sum_{l=1}^d \frac{\partial (\bm{\varphi}_i^k)_l}{\partial x_l} \cdot \theta_j\,dx = \int_\Omega \frac{\partial \varphi_i}{\partial x_k} \cdot \theta_j\,dx = \int_\Omega (\nabla \varphi_i)_k \cdot \theta_j\,dx. \end{equation*} As additional information we need the values of the pressure basis functions $\{\theta_j\}$ at the current quadrature point. These are evaluated by the following two lines: % \lstinputlisting[linerange={pressure_values_begin-pressure_values_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % Then, the actual matrix assembly is % \lstinputlisting[linerange={velocity_pressure_coupling_begin-velocity_pressure_coupling_end}, numbers=left]{../../examples/stokes-taylorhood.cc} % Line~\ref{li:stokes_taylorhood_compute_vp_element_matrix_row} computes the flat lexicographic index of $\bm{\varphi}_i^k$, and Line~\ref{li:stokes_taylorhood_compute_vp_element_matrix_column} computes the index for $\theta_j$ (remember that \cpp{_1} denotes the pressure basis). Finally, Lines~\ref{li:stokes_taylorhood_update_vp_element_matrix_a}--\ref{li:stokes_taylorhood_update_vp_element_matrix_b} then add the resulting terms to the matrix. \section{Interfaces for global function space basis} We will now present the full interface provided by a global basis in \dunemodule{dune-functions}. The interface decomposes in two parts: The user interface and the implementors interface. The user interface is what is exposed by an actual basis for use in application code. Any basis satisfying this interface is a valid global basis in the \dunemodule{dune-functions} sense. The implementors interface describes the reusable part of a basis which is given by a \emph{node-factory} in the following. This interface allows to embed the node-factory into a function space basis of a larger space. This can be used, e.g., to compose ansatz bases for mixed formulations, multicomponent problems, or coupled multi-physic problems. In the next sections we will first describe the user interface of a global basis and related classes. Then we describe the implementors interface for node-factories and two special node-factories that can be used to compose nested bases. Finally we describe some convenience methods that simplify the construction of composed bases for the user. \subsection{User interface of a \texttt{GlobalBasis}} We now describe the user interface provided by global bases and related types. Since there may be various implementations of those types, all class names used below are auxiliary names. We will group exported type names and related methods to simplify the presentation. In general each basis implementation may require its own specific data for construction. Hence we do not enforce an argument list for this. \begin{lstlisting} class GlobalBasis { public: GlobalBasis(); \end{lstlisting} As the global basis represents a function space defined on a grid view access to the latter is provided by the\texttt{gridView()} method while its type is exported as \texttt{GridView}. \begin{lstlisting} using GridView = ; const GridView& gridView() const; \end{lstlisting} One of the main functionalities of the global basis is to provide access to the basis functions. The latter are available via the local view interface. The \texttt{localView()} method returns a new object of type \texttt{LocalView}. After binding this object to a grid element from the respective grid view, it provides access to the restriction of all basis functions whose support has a nontrivial intersection with this element. For details on the \texttt{LocalView} interface see below. \begin{lstlisting} using LocalView = ; LocalView localView() const; \end{lstlisting} All basis functions accessible via a bound local view have a local index assigned to them. These local indices are zero-based, consecutive, and unique within the respective element. In order to associate global degrees of freedom to basis functions the local indices can be mapped to global indices. To facilitate hierarchical representations of the basis these global indices are in general multi-indices. The \texttt{localIndexSet()} method returns a new object of type \texttt{LocalIndexSet} that, after binding it to a local view, allows to map the local indices of all basis functions appearing in this local view to those global multi-indices. The interface of the \texttt{LocalIndexSet} is defined below. \begin{lstlisting} using LocalIndexSet = ; LocalIndexSet localIndexSet() const; \end{lstlisting} The total number of basis functions of the global basis is exported via the \texttt{dimension()} method. However, since the global indices are hierarchically structured multi-indices of type \texttt{MultiIndex}, this information is in general not sufficient to allocate hierarchical containers for storing, e.g., coefficients with respect to all basis functions. Because of this, the basis provides access to the structural information of those multi-indices via the \texttt{size(SizePrefix)} method. The given prefix takes the form of a multi-index itself. For a prefix $(p_1,\dots,p_k)$ the method returns the maximal value $q$ such that there is a global index of the form $(p_1,\dots,p_k,q-1,\dots)$. If there is no such $q$ the result is undefined, unless $(p_1,\dots,p_k)$ is itself one of the multi-indices. In this case the result is zero. In any case this corresponds to the number of direct children of the node $(p_1,\dots,p_k)$ in the index tree. For convenience there is also a method \texttt{size()} returning the same value the method with an empty prefix, i.e., \texttt{size(\{\})}. Since prefixes may have variable size, it is guaranteed that \texttt{SizePrefix} is always a \texttt{Dune::ReservedVector} where \texttt{k} is strictly larger than the maximal length of a multi-index. The result type of all size-related methods is exported as \texttt{size\_type}. \begin{lstlisting} using size_type = ; using SizePrefix = ; using MultiIndex = ; size_type dimension() const; size_type size() const; size_type size(const SizePrefix& prefix) const; \end{lstlisting} Finally, the basis exports its node-factory of type \texttt{NodeFactory} via the \texttt{nodeFactory()} method. The concept of a node-factory will be discussed below. \todo[inline]{Carsten:Do we require that this method exists?} \todo[inline]{Carsten:Do we require that each global basis is implemented using a factory?} \todo[inline]{Carsten:Do we require that GlobalBasis is always a DefaultGlobalBasis parametrized with the node factory?} \begin{lstlisting} using NodeFactory = ; const NodeFactory& nodeFactory() const; }; // end GlobalBasis \end{lstlisting} \subsection{User interface of a \texttt{LocalView}} We will now continue with the description of the interface of a local view as returned by \texttt{GlobalBasis::localView()}. Since a \texttt{LocalView} is not meant to be constructed manually, there is no interface for this. Instead, a \texttt{LocalView} can be obtained from the global basis via the \texttt{localView()} method. As a consequence the global basis of type \texttt{GlobalBasis} is known and exported by the \texttt{globalBasis()} method. \begin{lstlisting} class LocalView { public: using GlobalBasis = ; const GlobalBasis& globalBasis() const; \end{lstlisting} A local view is meant to provides access to all basis functions whose support has nontrivial intersection with a given element. These will be called \emph{local basis functions} in the following. To achieve this, the local view must first be bound to this element by calling \texttt{bind(Element)}. This call may incorporate expensive computations needed to setup the those local basis functions. The local view can be bound to another element by calling this method again. To set the local view to unbound state again, you can call the \texttt{unbind()} method. Notice that the local view will store a copy of the bound element that is accessible via \texttt{element()}. \begin{lstlisting} using GridView = typename GlobalBasis::GridView; using Element = typename GridView::template Codim<0>::Entity; void bind(const Element& e); const Element& element() const; void unbind(); \end{lstlisting} The total number of basis functions associated to the local view at the currently bound element is returned by \texttt{size()}. The result of calling this method in unbound state is undefined. To allow preallocation of buffers for local functions the \texttt{maxSize()} method returns the maximal of the \texttt{size()} method for all elements in the grid view associated to the global basis. This can be called in unbound state. \begin{lstlisting} using size_type = typename GlobalBasis::size_type; size_type size() const; size_type maxSize() const; \end{lstlisting} Finally access to the actual local basis functions are provided by the \texttt{tree()} method returning a reference to a \texttt{Tree} object. This encapsulates the basis functions in a hierarchical tree structure to also represent structured function spaces. While the tree itself can be queried in unbound state, the local view must be bound in order to use most of the trees methods. A detailed discussion of the interface of the tree object is given below. \begin{lstlisting} using Tree = ; const Tree& tree() const; }; // end LocalView \end{lstlisting} \subsection{User interface of a local ansatz \texttt{Tree}} The local view provides access to all local basis functions by exporting a \texttt{Tree} object. This implements a tree data structure using the foundation classes of the \dunemodule{dune-typetree} library. Using a tree allows to represent basis of spaces that have a nested product structure. This is important in many applications, e.g., in elastomechanics where a typical ansatz space is $\mathcal{S}_k^d$ where $\mathcal{S}_k$ is a $k$-th order scalar Lagrange space, for the stokes equation where the classical Taylor-Hood space is given by $(\mathcal{S}_{2}^d) \times \mathcal{S}_1$, or for multi-physics problems where one uses different ansatz spaces for each modeled quantity. A basis for all these nested product spaces can be represented in a tree data structure, where the actual local basis functions for each factor are associated to a leaf node in the tree. As a consequence the interface of leaf nodes provides some additional features. Both node types are not meant to be constructed by the user so there is no constructor in the interface. First we describe the interface shared by interior and leaf nodes. The \texttt{size()} method returns the total number of local basis functions within the subtree rooted at the present node. For each of these local basis functions the \texttt{localIndex(size\_type)} method given a unique index within all local basis functions within the full tree. The argument to this method is the lexicographic index of the local basis functions within the subtree and the result is the lexicographic index within the full tree. Hence the local indices of all basis functions within this subtree form a consecutive range. The first value in this rage,i.e., the result of \texttt{localIndex(0)} is also accessible via the \texttt{offset()} method. \todo[inline]{Is the offset() method part of the interface? Making it protected seems to be reasonable.} The result of these methods is undefined if the local view containing the tree is in unbound state. All these indices are of type \texttt{size\_type}. \begin{lstlisting} class BasisNode { public: using size_type = ; size_type size() const; size_type offset() const; size_type localIndex(size_type i) const; \end{lstlisting} For some computations it is important to identify individual nodes in the tree. To this end the node exports its path in the full tree via the \texttt{treePath()} method. The result is a tree path as defined in the \dunemodule{dune-typetree} module. It is possible to retrieve the node from the full tree by addressing it with its tree path. Notice that, to allow this functionality, the type \texttt{TreePath} will differ from node to node in general. If data needs to be attached to nodes, the \texttt{treeIndex()} can be used. The latter returns the lexicographic index of the node within the full tree in a fixed type for all nodes. These methods can also be used if the local view containing the tree is in unbound state. \begin{lstlisting} using TreePath = ; const TreePath& treePath() const; size_type treeIndex() const; }; // end BasisNode \end{lstlisting} Leaf nodes share the same interface as interior nodes. Additionally they provide access to the element the local view and thus the tree is bound to via the \texttt{element()} method. Probably most important is the \texttt{finiteElement()} method that gives access to the local finite element. The finite element itself provides access to the local basis functions by the finite element interface defined in the \dunemodule{dune-localfunctions} module. It is important to node that the lexicographic index of a basis function in a leaf node coincides with its number in the local finite element. \begin{lstlisting} class LeafBasisNode { public: // interface common with interior nodes using size_type = ; size_type size() const; size_type offset() const; size_type localIndex(size_type i) const; using TreePath = ; const TreePath& treePath() const; size_type treeIndex() const; using Element = ; using FiniteElement = ; const Element& element() const = 0; const FiniteElement& finiteElement() const = 0; }; // end LeafBasisNode \end{lstlisting} \subsection{User interface of a \texttt{LocalIndexSet}} The \texttt{LocalIndexSet} as returned by \texttt{GlobalBasis::localIndexSet()} provides access to global multi-indices for the local basis functions reachable from a local view. To this end the \texttt{LocalIndexSet} must first be bound to the \texttt{LocalView} using the \texttt{bind(LocalView)} method. Similar to the local view there is an \texttt{unbind()} method and the bound on local view can be accessed using the \texttt{localView()} method. \begin{lstlisting} class LocalIndexSet { public: using LocalView = ; const LocalView& localView() const; void bind(const LocalView& localView); void unbind(); \end{lstlisting} If the local index set is in bound state the \texttt{size()} method can be used to query the number of local basis functions in the bound local view. This is a simple shortcut for \texttt{localView().size()} and \texttt{localView().tree().size()}. For any of these local basis functions the global multi-index is provided by the \texttt{index(size\_type)} method. The argument for this method is the local index of the basis function within the tree as returned by the \texttt{BasisNode::localIndex(size\_type)} method. \begin{lstlisting} using MultiIndex = ; using size_type = ; size_type size() const; MultiIndex index(size_type i) const; }; // end LocalIndexSet \end{lstlisting} We now give a short example on how to use the interface to compute global indices for local basis functions of a given \texttt{globalBasis} at a given \texttt{element}. If we want to compute the global index of the \texttt{i}-th local basis function in the finite element attached to a leaf node this can be done by the following snippet. \begin{lstlisting} // create a LocalView and a LocalIndexSet auto localView = basis.localView(); auto localIndexSet = basis.localIndexSet(); // bind the LocalView to the element and the LocalIndexSet to the LocalView localView.bind(element); localIndexSet.bind(localView); // obtain the basis tree const auto& node = localView.tree(); // compute local index of local basis function within the tree auto localIndex = node.localIndex(i); // compute global index of local basis function auto globalIndex = localIndex.index(i); \end{lstlisting} Here we assumed that we do not have a nested local ansatz tree such that the \texttt{tree()} method directly returns a \texttt{LeafBasisNode}. In this case \texttt{localIndex} coincides with \texttt{i}. In the more general case of a nontrivial product space we must first retrieve the leaf node corresponding to the desired factor in the product space. This can be done using the tree path for this node. If, for example, we have a Taylor-Hood element, where the first child in the tree corresponds to the velocity, which itself has $dim$ children for the velocity components, the leaf node for the second velocity component can be obtained by the following. \begin{lstlisting} // import namespace with index constants using namespace TypeTree::Indices; // generate tree path for 2nd component of the velocity tree auto treePath = TypeTree::hybridTreePath(_0, 1); // obtain the desired leaf node in the basis tree const auto& node = TypeTree::child(localView.tree(), treePath); \end{lstlisting} Notice that we used the index constants \texttt{\_0} from the namespace \texttt{TypeTree::Indices} to address the velocity node because the tree root is a hybrid container whose child nodes for velocity and pressure are of different type. \subsection{Implementors interface of a \texttt{NodeFactory}} \subsection{Implementors interface of a \texttt{NodeIndexSet}} \bibliographystyle{plainnat} \bibliography{dune-functions-manual} \end{document} dune-functions-2.5.1/doc/manual/gfx/000077500000000000000000000000001313314422100172605ustar00rootroot00000000000000dune-functions-2.5.1/doc/manual/gfx/driven_cavity.pdf000066400000000000000000000024201313314422100226170ustar00rootroot00000000000000%PDF-1.4 % 3 0 obj << /Length 4 0 R /Filter /FlateDecode >> stream xMO0 >#Ďu 8;l8钮jߧq7S(o[}6x~4Lsʾlr1uڋ;{舯D:;>O;vJBe5܌Ӣn!&ncJ;ת;Pk > endstream endobj 4 0 obj 396 endobj 2 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> >> endobj 5 0 obj << /Type /Page /Parent 1 0 R /MediaBox [ 0 0 307.858551 286.171478 ] /Contents 3 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 2 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 5 0 R ] /Count 1 >> endobj 6 0 obj << /Creator (cairo 1.14.2 (http://cairographics.org)) /Producer (cairo 1.14.2 (http://cairographics.org)) >> endobj 7 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 8 0000000000 65535 f 0000000810 00000 n 0000000510 00000 n 0000000015 00000 n 0000000488 00000 n 0000000582 00000 n 0000000875 00000 n 0000001002 00000 n trailer << /Size 8 /Root 7 0 R /Info 6 0 R >> startxref 1054 %%EOF dune-functions-2.5.1/doc/manual/gfx/driven_cavity_result.png000066400000000000000000004374601313314422100242500ustar00rootroot00000000000000PNG  IHDR0qsBITO pHYs+ IDATxy?} `DDc.TwdO#BDQAn¡'g<"'1FEA̡\]fGMTWU3 yޙwߪRLDXbŊ+b7 VXbŊ CXbŊ[11dtI' bŊ+V˕"c8;sE  d E|٢dJWvS~٨*T윩AՑHPmL:'tW S[r.p[[pOə*Tl-V7/djt_\>> 2'45j5k3de.<–3GX˕c0I֪[,.awSlbvC]-kY:ت3iDr*M2-_6v'W~bigr*srߡn-V&Ռ+V4l. w\Ƹ( .;8w)OWk#|L(uA!VˁN G\a-\p~ yYV[_\>zMrAa PxuZ 2BXE!pX 9F"D۞tΏs4(.. eyVEm\Z>z bړU=#DwB*$"L2WspTOm/74XZ<Z@p\sޯ\!={9?( Ņqb3B'1TZȐk0~"Ǐ%ѢA!V( qCD <ɉ P{hP%D*%_懗bJ9*]?.h  [8`@B8A<\$ I(ܻ),bJ+VPɉ  Z8'PO_r2^0apRm'ڲ0pbxw ).Ob`d`9ȵX(ݎȊjb o -)^bŊ@Q 'VzV{|є-x< D 'W\4~Up.* =*e8JoA!VcFjH1ODD i!ϣ28e;( V> I)'䮯EMSBXǤ|^YH1.l{*2- uxk0lZZ1p| `(zHx(Q0b:2VB m-d? $qܔFnI 7LNb lYzȪI 9J($o$lĊUXE̱F d w6Բ뜬A<"8.IxT3{ UFL ܺ-!h'.0de{Kfp{ ҔtnGa.yZhy/7U&u(m g?C( !gmu I\| hULZB?SFn <+ C cl~ʗ8Ww.]8+k ;ւA .d.H ڻ+; |.ڶ9k{2AzD`piQ*fEq)!h+q,'t䇚WW㘕̋@"yK6>37&ٌB+Զ`*-&Gf7 kM5rZyGd__? ϨXC}#uGPm^VqDk8%^c&͑X ]glə,(pJV0$G&WWpHgH0ScJǭ |n6bkzS*E8v$"d;Kmf;|8ҡxDh\pfdgz VҖO_r).$YciIף+?n|Th밠+IdTl]?ap_E']Ka|j-MM=TDl\p` }Deĵ3@H"TbŊu|*K \H@U9BfA)4#)+7._=(*غ~…×W),뚼h>qaҜa&h-X{3j:c\p)OS< ID![&Kb?V+RC%Wן,c&aفcجs؁.87Z@@\9\ Z: \띾~{ n0DnV[~L{+V|cG@ `Yk/+h(Aq dd-d-,@W>|PQւU%}C>ܙ4$f W#  y[ǺO`OTb_xUL$&n󽓵 FKJE NȎ.oAqYQBizD\i0p򙾰d I IU!UT -)5VKĊˏ2 &1prBqUf0 BS~pAL\4wxZ`|qfE *:lx a{.CZb{Σ}dXbPHC7CU/gz~HXθv4$AJ0|FråBl(w3UWE’Y#gIŅ$$}RSazD.cy!Xrc`zz_݉@ ÅdJ$TL7k0p! dP@q5o\Ȟ;3}AxKCa b(鵢` +Wfw((AQLU(o>]V [O0(yA\c@q!Bj&{{ۺ,l#ld$.L;\Pu7HGQjq`r#=O.o ׮`Jŝ]b\u%QW)-ٔ ߒ|NgZt}tsx}u?[ V tEQ؁?[1HZHI^Hqa\7k^p]F]ce8k0\>ҶPTxD$ (PcT#AB+Ody'] y@bױwFeN! a\ИޛVe-dL9`E(HHMbLiđ-Vj.iR#3GUX˕Q31*x!N{,.3VV#Í;]߾1'+I\/4%vD{u]eRkA NB'Zȶ ޸ vό_ ;󧏚䰖g߅Ox _nUaBL+VcM=R҆SvHA-UYoEV@.ҶQ}lgwhϟ782bkӴM%4(vJAqja=3ξ NuQ9#Xa #c?,AlH"@£ï.p06QfabUg/_UǟUkY{ȋ  6ElN:`ovNziaױ_{}Qέ+wc.z `Y "+|ѣ?k! SzGO0{ چdڒ[\ϛéi|fb0x&.@{;A׆j%GfJ']e4呾@E7;#8!o$oݹ!ZNyC0g:Vл[zW ӽk?ڢkgt{t(H'ҀtN6ѿvW=nࡢW_lj.Vޔb5_Do6vAmօiKtz .d#.gP Y >w#:k#d Y Z႓[W$oHX n}_zV"0{jj7MK꿚LS<LH# lɗ}ŚTMЫSGCss11F@pz8a<3w(W-Ӧu=Gk]RӻK'^^p"eޒc@c?0f2Vӧkg hRd3`qkTf]i._$_CO`ۀA i*ڹ`17|zjm$LOl>W(<7<5zܰvH뚒J:W8ES;)ʟ] -62F!|'.H#ZpOQR\uEkI x?t NR|uJQNmT@_]{#$;A.knHVXUsHremeg*mеšQ,VIw;龚$M$>l?(=t2rJXLLj*mIpϾ,=tw`a(ћ%4 yx3 Xў##s#5wRڮ~E!Ӏi<ܜ.^p 3mL7־fis v?;RT]n쩩'këXn؞JJ# hlF傫N& M[FSL4JLfǰ[ hXT6mdj}SS)3)b-lgwA' Db(&A: Ntz]2< {[k.i(%`un_22@ʕh(}A=.a 4K~ء =l"* `]ŨTת~x}bI=V+v.Y-;`ԓm62[ڥ~ dFg P~^M=vBpsR: y&~zuH~C?TQT~„*Џi@!+*;( ~~N"QxB9q CFlh$V d>zózN r\"mKj:`gn0ɣSH"'$a)Z3ܭ{HB< W6B EHmc>ゕlሁ+X0ELQ o/?do `s:>< Y`q4洆FBb,787詩H0@pæ̳> +*+ taZl%.]p>X!{H0U!l̓\$ٙĖsX Cf }(TՉ>iX _V5?sBR-^ r$SzEj9!MZC@o[(=U}Ohk6#4I+0=Ή Y\nx{rw]+LrB0İ|# .on-؂֛K.k?%S,OY buN?wUz% .4*G58C7}w)`@ ! kۧ>k%& oym8EWi0]B\M4e ۋ÷j'f|>#WQ"~AA$ӊ-g1QA衭H!h,F43Ɖr 8C WZe@ C8| t8nl Rn =7(A +K.8rX{Cٴnl DkBnR8 xR0DV&ӰT sEwr[ֳ-1~V6l:$%I:Jq8>`İUdb'Q LH\hj`2ձւm|z&m{+qO\`KvoGB`)1}-pɬU'=W_)I%zObȇ Mx5?YpCiN>q?_u\j/Ϳ7(1YڅĔ]G|壝'$Ҟ١GsKٺ~F?B+bTwK:SƃSiU`6ةE"&7l {F @0 $Y '.I\`=^5gBN@!0;3$ ]W_" Ru='\HE ܥsG=g䑶1^_&E֐-ܰ)1az[2 N̍/LrC8b`?]U>*Ul"w\hƃ9aMdsjyI,%a{~Ӟ lٚÌáz-Za%)<7kyĠoy^>aZii\(|D!##%8>{7İ7<Jߞz1]ܰWt:gϐDQWu)!mk<^~L(䉜*4N\cFž%C,V b_Evgܠz飃+B8#)P4LI_Aw!_B^:ng~)HA @S#9n R`n(pB4PxýVúalz#f-p,|!lnشb5J++[]J\p .Ul]O4ے:%@LH T[@7M;J>p!m,5i}d!В\;I\00(U2 1n3 @]>JBIS=GbQdx?Բ|Á(YEKRmp)ΐNOUݵd(pgCCUifz|"FSƒV]X qCXk~=P @v7"ldʠ({Mi@J $$ łؤH6H$ ̱.eΏRnȝrǖW~6-!-H+1?~4W=q,-W'1l=:SSō=TTM-R{hcQ2pG sbƳ0 Cـf>4w\DnN/WC"# 0 d1e޲B GnF&ew65ҴZO>bYbkQ.'h?;C*$SR-ICOG .VfmRTבIЀ_u;9T]hbX]ǹ8=c-(BOX] ԇiS'q:3Wwa}KؖL}Yb|ͮ]<0@7}$HښwH"Gb:kӞ2*1cO N31l?lA"h7DK NI\"^&WOXU;V1.)~9'H 0$ܹCsYUi (FrCİ G9[ svl#[/d5 l߸Óڶ\~K9\ bL;H^?$Ub{ۣduJ7w.d~& Rl̓>C6Tժ!uo>[|&Vݽ ȈAZ0Wdv C %mU{zJg9MM11c$)y+c66ݶWHAu] h(JrC$p[. ( "kL~ϻli'ݸIZ)[E;FKU*m^N&pfΩxs~EL$1Lױ'.@F sU_'],&T2__wtwm HAӭMs9 xRbr:[,F е]U_6 (1S1ҩ:Q8&>\"VL[vWմm69F{݇p1vv NpJU-RE|ԿE ke'{PҔ ҪbVZ ֢taj5Npa/@=)wHSbxFzp4ؒw^5$7-p#.)6`╗B&=UP ú1C &<죪?-IЙkWZ- u\i}KJ~gZOUw 9QzXY>t4wrYÑ#4te#is2o@: >n.KTS4s>lM ;+@&Xױc! IJu ]qGRGn{OP('Xzϐ8k?ۙU7 [U$ޜS#}Lq=nk Ņ˄ž)kXTVYi ZʷS%V 'i@M<>j6N*E&8q4I`UQf{E1U+`q q詩\5rSǝUi*JNSTM=*J Aљw\֜$[_\>DQɆӴ#+.",+p' QUaVX4L$~6V;mI+H'*nTz?EUȷݑ9D<ewS~ӽ%ޭZPZjz%+*w&֯冮r4;(JHvnf*@y5dՊ+*[B\pՔI7. 4hՊħAP,P_ft> .J2e;oo}m~7/dS2|i @KjiSc,'H:+1v&%]>gMSWEXU+.^b{*ը(Jz _U+Lܓ456>K}ޖsV;RuےIz b2cnkya0KBZ0澓g_ڹM{ dM*k4nNf&G)ź8"Ey[l :wySt'\p[{$`/oi 57Wn#o&I 2mܘbBWTeMgI-.HUQί0U+v@@094D4z%A|6pLNV2z;T/߇ (n@0&{>n~MIgYHZ@ p38e8xa8L Kye}ʾ y`#~'pCiC\+XQ8lp4mG6 BÖ1FrfTD `(J_>i8ESEThZW#£ .=D57 +t~UbY2\Y2\ (pA Kf@rȜ9`[XNӤO 38!L~ |OC y'ۆKDCivTb=0`3u#i ڝ50B\ ܙY!Bh$7A$I( ũk De*tq@82߸0Y|;:4|mg9N-=췓5@]p! :uZzW 1=ĊV%VХz;nؙ;RaЁh*0eW*uC"BfwȮ>w?2fS; Afl\zκ݊FLY+ag\papa/IqXg<qEo'12S٫;!$PaT=4'1@#XcS#^v*=j{j.WJU:l衩QASǑծT 2r|F }t @;]oʌ 5Z @X{(>ͳԟ͖x`j9?\>q8/\kI\tvt~;m *:(AC\]Q<ʷbz|, aV^_5r4*Ud)AM_]g9Np4aک*C #nTfjg69eYjHEaOeC (JY  Xn /PQ \L  h̓DA@ !w&R՗6AE8 0T)fkkFȹ*ZL3ZKcE DhS We 7d,1<ҵgvCDtDܡ}I.5-6OSz#{YeE<[FVMvR-k@FXfCUxw.xt5)|+FX-VqME唪O}/$ӥLC涜6>N|CX K(a~&ik˂p=i&*4?+.8)t ih9a˷Zk8wS?XN|REyh;UM$ ub}Xf \ *-gQcC1:jze REyvd9 i&q p03OjyοzUFxEX $wAą&G;Kz b0k₳`69d#ṉtحttU+VGKUO7ѯH'7w_vwڒD\.6@P Cga b3 _.ȭ1ϲr2ym6wKڵ .(3)zfNSQ5a\py,੨%qcL1::Æʝfɐ@CB/+Ai0ILÚCusFa'P.a3s4mjlcQ^H\h?MZR\4s:Nla 'EnT?es( ?73M1::Uz%wS-*9֭0g*b N4o Rpg a3aM".8ܰ߿iiFpaalO:;S\j՚׋ڀ_X-Aiz]:SbxrQw65P^2[[.=SO vR~3_uM O0tְ o jVy `T]M<.v93vEطaɵN @Á I`KԊ^:h8xa~bA i0|J筐5c&2Et$O@ EK$IdW% 53;wpAڀ/tȡQ_ڴI577F[5غhW; ̗bMgΪ4TEtnuݛя1V @^fgڋ9Nc͓b9~{ o1go}(,((&)GbH655H|g/ gtj;~H|w ]U5,zxNZpK ե_֑a<#O _^.Qzt}Á^O&,]<ϣ+;%%TAӦ8ćiýOw._M^(HQhA'BN?FG{jIm` =5[ө3&vN$Nj'] h7j ?E-.4QCl9f-dK:Ѫ=+!/`M] Z pa S +{0mnpؖ76S=qtzg:}[h5W5 Oj0W եs:s`e@լ` O莛'_!*NNiLD{ѯ_]{M?z2ffM$Xz:p0~66u rCBN*ٰӈ 45m57TTv +*OVU'9 ݝlT`SMdtӵۚVf8M. }::θ@Kuu*`NAf5,Cb6~B6}6"PsbOu?SN! (Q$clؐsu: =>CDUxt IDATAQJiSH&xu\4Q (WW6&OCQ ǴWRwՌs D TFUa]j@᱊J]~/@b]Ee{EQD pBjr"SSj!|98ES;Ph4ͣuVڞiS ah7bx&XTM͌AuB K4WpSZ2< kj&fW<.n0 S;HܻPwq F]3@[ S0+J< :myb@Niyሁ=1å @ +9N lkpE&VpX=| W!OzSCqaqEVE[F_N$ݏ?h8?18QQKM bx!"ϩ Tmf y6$Ʀ>y",8 qVzEKO`$1ϸlOBm,C鍔XtH0s; bȶJ):N lß{9|8"$d0y|e8h`U0ںCsTq:JX8\!ߩE70B̆BF( [nj?K׾H 1&CARP++LfvĶ8&iIĬ E~ơ)G k:n>_s r3ͅ!>dfھLcZC#6o3g`?܌.d:գbzxp0жNfhbZPmg?WSj DXtfS&-z6-^Q<yP 7L{jja3t *BC!#Ņ&<nN6[R2zTgI! m }r历ÓKA0O͒!UaFXzh( ĝ?{gεӤ1 Z`Jq Yzq*!5?^Mrc. >W5-Y'iĿxX'1\X[`/^hvj wn =\P[G\W^Yt(7,R+ o67P؄1\G%;SBp#­' {p!]4HJ5zMP=Zξ/ڪjinm>3l׆%Ƶz7s|j;C43C@krx;zu^2: V k2 a>r\i}%YDǎ p0Ѓ1vbiӯ [p]\X[ A(G'0O.@U(UA EA65y) ]T`/E`/ ŊM"0z 4™فoaJs ܟѹqeHCkZi~J=ٜw&\wT s6:5Ͽ Vx]";?3A]̄|[;)\(j0La8M*݌.d{rL߭lG6݆U~ Ҫnj˥ډVnѐd]+k5/_E`t zb,,zN-kP1BqrNz7jΩsػpC^S#YĴ"Bly}M!c1p GR 7(Y0c¦&(ڝ6;c.&?zqntu4 :`>yZ@.aד?W]F@zaO@޳=:dn}%-r+ .s>GO^)F[ xu]'_Qx dpzU@ hdc=4szxa^U5Dnp÷j6M(C1Yh@0fC#E&<}%?L^M O8)gv˂Zڪdrwx-:ofi3\\@%r?1vK@|-޻GoNkk:M@r!P;U ~3g̚:*M~:\>%wY,p)I>Rt `N?I BBmTrrAskK~Y\(/ ll(4x6; 4NR5=;P⭙H d&Wa .A4;\Jb0ąkeJ'kՃ=C=jUxGᰑ7ȸC.s7q$[2ؾoXh6"Fl۲(AplV2~9LDhp:@1tŠmE@DGL:x T!ܚL]|C >s=ďš ŊP   ~!*}CloOHvفg= pvpSp u3ג0TS12AO\jo0̾ߐap֪AU0L?mdHP/۶'_Oқ5ᆷS]Wxr4d R{>OXƃ=n5rChbזn!V9A]ڼT547)J$ =`YDjtG=STl(bA;ز bx]|g*p{~{zvD㭏K6H "(:uv b<}O\/AR`B.Y8W~Lr9h39 j Ok71f<8zk걱þ_Rnh0?.Xb&ѣ\Ѓ,!Bb [xv釁R|F/aup8 \ Hrdan 27jH׭@Ѐd6`eQMu11aR]<1+j-P~?w U?K!/N\ ;~ Z8AvS9s'?M,Gu|(aݩNw/A0@h(nyzsC=ĘJ0L7^Q+zjM@JE,}dVqڔpI!nCjREA(h(P@C& F%Mۛ3kP} ;(@S \A?=놜lUS7}/ ȉₓ^l;<*bm@L 76T'`1 qEWPEAm߅\%*Xna6 x/BWŚXh(DCFHb*t%²mx\;ITHpvo>CG3qw,CN}lN}iy_P?ߗ1[u_zuar+H]U-暼JŘڶmv-_wðxPgyxnKoM=-~jꃚ W3$M$ܼh>UQf|>(4 [v~~r^͆Zej'5BQz冊455Rb"RRݾrtG}sSvh廷چV:"b7}I/]7Qd\q!2!w\gJH+B IkGVnLKy s)|jڀުz5/]}nbCT t:+*g%LQ㡧vSU3Pӭ{Z@sL9?1~eᝆ|&</*|kqoLqAӒgV(Mē%W\@(b(. (1 IHrh?<~Vlg%Z[hXrXYq0Abnx3l/ˉ~9n|tnuHi &D%?<&dtc~~XRPp|z{p9NQ֧Dx]S!\H}Ċ%-\8mM7IЁ+N"Hn6*p0; qΨ=6U+6TTS4*1U59X`U+Dd'+LEU1_w~9 k@T=#~3|7]! ^U|L<OKG]pJ L  ߸o~(gQk:@ t7U=ojs׺Ԙ㍯`  wqCkXCݩn`@0jJ"7hQ&6wBM@k|[紬z"'pLYUF\V:}jG I|.; Ii9C><yhîC4Z\m0G~MFnU'~34P4R)"1gJ5 d1tPnv Ný dPn`.,H×O`!FmˋyGdّJ!Yp\ȣ͏H]j2 lqG*6aaEY%mDQ(ص,7 aO*kB BT iN!BMohJ H$>MN:hi:\8DpCzk ^CAO_#=Wg38}9h迵 :g#\ֶe^/O%x> ږJL|g]@hݵ~IBsCC^S@eC7dArrWhc BC8A:iJT b61|t8'1Pu=` j<$5"X\.1\ΡM@v;)cSf=:tXmG<@CANxqC#rѤU`3\z%A lag:30O.ޣ+{'qhI{l`6#P.7;m|'P$$!W.FmXeK?ilݛ| l]j58A*b*i)!͝?or$nD]i+Vg6ĔS\QGH|OrOh fREB|g3OJ='sb3o'$:H=9%J'n"(ݜψncb~mppp IX]RBqհ/:|bAcp)A IDAT?Xþa# SE E" .B[x\("%uq1vcUrxb.%Ӓ>9 $N*:*Ukѕd鞚fi>1m@IA6awļo>·zեnO=pgRi}TMJ_x9ΝO>ZڥX{tz=PïܑͮłΝ 7Lb=y;eI,4Xg;"8.l`~YUdgͣ(|o-uІ$VIl  f߼!$uW/ꭺ[{{wfH l6kHK?2;*ʬ{~Q;3"2*㓿%fO>*crt 9o>=vV]PƢ!#% g nԎ}pGnx_[s`^SB. `fE3AmsɄ8 R>\Q&8Y 4 D9{҄ޱY~~WExĊ@ߙSGޅo}(~]MguegsϷ۷]Nl|\.mߴ m]5dZEKiuPvYsxpis{7h<7  7C2t>]Uc -yo?Ee>]x2ǫZiBp01x|lǧAmnݸrCfez\U;-{+ Gz.}/eA?F&6,?9kӟp4_DqUU3e c*0+3 `fy|!;2T ̐%6~3m>[?) 3 }~7giG  R3C5e,MQUi7Lq_ֺGkj&K)-4on=KJM"זJ|x.UǾ/*Et,Szl[B0cX dif'E>w&B>߇Ƣˆd)"I&qNQjA^^O6. c~y߆tyƛ2ˢ&d|Q6@U<.\ 'Z;)CH>nX n6:l㏗^Yq0 ipC}K$Tcy `r^0MLRu*%Z,hx1Uw2D-4nho7,"D!’xlIxM&}&"!m/e `f_nm~=ϏxrBTB+2,tnَU?PNBjɃY_xrB$K\X))o"1xF!0@> ~F~ fҴѣpžR("7 v6fC@e4^[_ޑ c)}] U Rz0mGM\YDM _!f6 Y&}xGo<0VOk6yma=;0W#/]u"9+d7:ǣyYU3+ZюV#?IU9$V0t=0jOXn倨 g^? ~났OUՔ ?Oł'jgI=GM&Rc\UG JOlp1RpWH+'18,FO M%LjK'~u᭣Jmm.",^ׂhƊ%MákiZ4ï~rW֤1~ܷ1t1K5Ӛޫ %xtp+Z`7o6:xF+ ĿWV3KB<TUD"1hR`h(VlIUV_(_U:4M 3l;QbW*e4N~>? Md);!$X##vIXÅ _߇H_IŹ~QXC]^]|zI@ TUhjC,ͻ Ug㉪VXqL0rBËQ F1d-OM&&u3xB&n~8D(A pKi[R5X=B {IbN0eǪٮrɅ!(Y@N\2~=>VoNps\͢`d񛵝>,cъe9v &5C?ݐ!i$2"n@b `ܰZ@Άj ( ,628mv3覹nİ2o{71XR=N0bX70p&R"X0+ suo;F b<:xowղꖯ eiyt:nc4bpTUgw9εw^-p穎1TlnH/PHg uY|K&L(6ʂfGi!| a-OO5'ʰi0e2aNz-b8W&j!!k,|p3?⹺@GfxmHf  {T?Y,:~ziNpUNcf LxZ'DɅ*'ēMdy!UWgç :R"CX`7Cb؛pTB1Ob$V-k7Cw>=]q*`?jz(\@ ~0|:0nءIp¢ .`Ϥ:! K-3c<,b`b\sl^qC>&܀dԑ9-.dU-{ `Ά"w*beVo,11[O<`&I5KMS b'C0ĽX+ Gp;kf_|6Vw9BVDP)9N&q1npAC1JB߯uQ!K-u;E?)Xp}@@hW@R @!N!bDq *P|X3D&>6i!9@b0 ^Yo8!)pc 1$ș"dC, "rB.Q/ aӃrx]"~VC)ɗy}.np?<:E+lt`74|<'Eh`_ ta|8fTJ`F>-ɑ 0E8  PUP||bw`V,cb?\d\ŋlb!1Ķ # y!vsϲt-?B{oW.f/DV1dIMUvCi ṡ}N!vӁ Xp̤qsCXb`½ߪƧ9E!I%r*1 E[gl+11ciOxE ,rD|Npv61DPb NZ:At"f9p|!-2.!0wd%A /l] N/U`KW,Q*?]E 9\Yn?nHQ%{rC>, ThO䆫ҭ}!H0CC;%2gy$pE? ~g45&k~k>Ѽ߀? հxG^˵paҍ/p>B7vAh_,𫺥\;Y:!ϝޭf/=])ӬcS%f-nn`Ά߮Oj=uKa B cym%+ċ>]n4x1UWBO*P|K? dB`ΚL,Z$*D;t}Sȁq\qז<>Gw9ЍvƅMK Pgi4̓]Dm+c.d?쿬yQGM-MO7=])Nd?)t`r!`6W}ݜKԽ}n8rM-鸻p >  _tI B (}0IӔ83 JxQb%03k^Ra<30xg!zY[1᩸> y ; ^\ )aR8\ l9M:=e|$YYQ$*^̑(pRCFL:NTHEˢ )#$ 3]&I 1d7`swy{>xqzݧ/*U6TK4&ux30XC!B[hu|Eaa1$1ގ7/7&KG <&2Hĭ= ~>P`\k] -sgEi.w^e@w&skj2tV6D2Mz\Iw&4tבc [3eXU%ɻ[ף}o\jI+ ٮOCap! QkaFA', 4yh8Bv/j=MרJg]B[UR:I8`lCsǬg&;O B|\F~<58Å#h 46?1q>]."29W׬.ܼfũl, v]9oZEp0|=mU {qnk=]tݵn-6J65 `n)M) Pʠ!KcpӔS, f7hVHu7ʊ4 ITCΗgfz: "@ac(ъ2@!f5hԖ;V,>n٤aM#qO_byF?8[&Y_ 9"'Evi$a &Qgx :Xp.K "w_VUp1H!@_̆,QAa Ve> T&&j4ݙ?*crb1f?枞nMJI"uxWxn>y9gQKG~/P>3DYQ6m;q#l^zhBN j=`EÅlSފl(.4nnC&f!ɳ"{~XU7Άء ,6/4`4Loj9$pQc^d"%fXkg5}|6#L?H,*`P{)=d'{dL 6ƥר*4Ztyr#v;h~ށNJUa"~9OD|Y9N2WBJ؊ 'j*$y"/R]VAI֋c$KH\^LfU:ۺ0ťJ;_˷I<JS #W}?Dvf%<8oCW$:EÆ/Snvox,pׯ…M-O;HhBl%%m+ ."`1;2.n(L֐2l1AÏMcQU4s-c5!4pR nYȄ3@!`#n,^Eb k[uwHx\k~r KC !b)_XU%\ ի*.I;pYq!Y+8  M4xt(#dp)!Pշ bi-aCAM,x1U7A|lҩwC͐ecB7.PDOLlfRcn˧mކ0ᆀ9kb,O/t~͏- 9M Otϔϒ]m9E$S!Dl^ w17?uH 5`ݷJt.ߵP\쳚eX&@1 ;o<: YhK{:qX,h<7kf_ BY n7C,pg @tG"!`*q-3n<ڂlY(@QGNiӥ6*g$47lyj^^U^#5mj`n⸐w!}^!g m)[$G4[Uo.+d#@ 8g5 4ƒ7B&aLC:嶟RVg(ohLquHB8O=E 6ꦀcyr8Ѱ|W(gfp)*+~81p][#`FrXg@9-?\v0XB F4 bZ߬l:w6АlTࡁqe 0IւfXGU5 Ubc1`>CyzcDon>C kN*Ia@710݆>s6$P FBV0]12)LchAQ"mKxѲ0#6>?(L-Trħ@W^1h c݈bw6IVxh(5~Ƹ)l=1Iw3m!ԎAgRD#+)ʠi0lfL-^ͤ Ab89 {qatJ~WC 8wOON98fi;6ڏm-_JF߬ kU}/yHX(Y6nkm=Dm6CC~M%X&'4ܐnd kӭ kX0/ChɛlpC$!dFS`~^j,gf`#o10G~$JL:7 +̛L8cPd% \n+<4YLFJJr*j_ngdaFSzm%%'f{ RSwR:jIV>Ü#K( A ' BmZ[<7 pS?;s[\#A-LKJڭiҴ paG Y3 ]d[H_su!/H &p60hTِ{-!śei<6A}G1ACTTIb¸~ϕ75h4̔DWeKT)ݸĀf1 F q瀃 x\~As+ %9>w$7_bM C.ʪT Q<ѡv]?;)".& qγJ?qQq`"%-!OXYC84$MS\$s3%wt?uXtv320t3<4İ4&n<0 ?b1 cȇDT x}E }fB8rȍ ׶~]Rf9!B!v^7KЎ`rZˤ=l1'KŠ![K- 9\x7gjy㙇?f骚rB4̔b20㡡ĀalS$Y &$B1.x&>д|Yt0x!,7=au- <.xz.gK~ZFhEVûpkk}/ 𻵹6MǨI@̬R')%4E{:(}0e>K](uA_K|* \RƆy`  E@ EF]8 e`b7$E?-DJ7PLS8ӸU1|ǀW $d,L RTol!G;)`G(NR"IW4'ޯ;6ͽ~:0M8@IWyިp-;:c`!"fS5W3l$4!ga8 aK3Y xpAܢ}gCzzBҬtgpQColMj7\}qjSnFdWn81[Ih{Qy` D~Uv6xx*@Xbu @4{Tru 10Pb[Pg÷4C"ʞ!H"ycfaqAp]nܶ0wq<~4,l^x ('d,_!V ;zn=׍cJonߗ u֨2 i{;1LQԒlte9~28T0g=wuwഐÄ\&qQOGQ< V`$fPH ^ÀÌrݖ!6X< cjQ~n6ukֲ/*`6t0?xc.ɑ#=+QO]˶r gkiNOQzByܯN W}1se_< vڐu=r6L4vgYE?^𦮟~8SUE4KYLK R!oa89TWJK#}10KH!#+Kf4! g!R~%xT]0q\1x]Algz[ViĢyi;cwuu6.\:],x9|_~ !&n`tK!Ak q;lp_YŪX{ۋ"h(Vf * 1 x#j4RrB"PL^Cs𑹭Mn޸1@B`qE"B߉ FŸat 7COYO(R\ }IvY斖ɍ3NšA RQG) 3sݝ}j6T#ҍ--W!껻;(uTk7BXp44hDat@ƨi|i~`IуD%XQhˋpG%4YEWB)jk0:<1q2泣UX A`" <_~αiXb$M"_ԄW+\2"nEC%0I0>D4 RHg݅ SD 9~If^JngwjB^DQTʴLHޭkߒ*FQ c($4C9{ŝ\#F s)`8d)XBr07 )W3rDYi IDATDfAwR'x`@.?y[_ `>'sp[h<-p0Y=@C.+7"yV6\ؔ.# Tm%Dz9UW`h(f2 T-e`<-1 B !Z,&&%v^R=ƍ9nbȜu u"SgqA#Z6A"4t\2\͏BL>5n8ujMݫF^wh!&J<^\h( X61:Ndw(=S>&+k_)RW,P$D(qC1ZvHCg t,еS sRWڱ5,.~oޢ-YOZ6 b*֬jC.龣bÆyؒS!v5=]La #~ʤq;w[pzDs BfOD5[f5+B~gw{5 WA򙖅@55 fي64q~H)9+6qh ÕID,S%2S 79h c3eIfDj*!C8BtϙǗ77 c "Lklyt`ЁqSDSz@CoǞvSZ2mnpCCvWw'߻ <4\n1λڣNSz:sɨ K^̪5h!6T Pxh( !,G򴚭#ct{_W5(&>y~g&xy,ұg`X%F$Xɻ>@@Z4x8n`pw֥ާ NRzR W9^݆S&e q4[ 4x .4H}{<CCQ6,|劭tt3T&01:Lwtu"upHI~ Bd7 qCS-ݺ1.708Ef3.x>`E#_~ӃaԍCI˝Yq٪{ D~ I@]ݝo[ F رCxep/y[ڦ46 n7Cw|4\04ׂ,@lv3r 0,]*C(x0P"M(c=+`%C h!+W /eF 0 s~XW}NhY^Jf#tiU  s6 pl0J`eFUdݤ}yCo<* a'=X>o8E IDU+DVHlEOtY.I['Zԙw0HeUu* yʤOH!G"He VIlG׳;ˤ'rBS/jVU7[>M$`{W$U{UCߡ8kK(}eԢg(7{:PJHҩϴ, Vݺ{Kcb4纹hђwwnj.IUn;D7uiR64z T"D)aK07r[BKt0C sRpEV-=ZqVۚ?TVl>C&ToF!KJ +vs hIbي7d$H|%hbæ9MNS:~˛[b6C#3!dQ\(cSlulY"&4AxiU#y~SKeUiL ?,n\ }/ X=Gn#XD.k͘)KWV:Il`FĜYAXG=o~cą$"v˹ʞGnhA\s0dN+v~ƀi5g+X ₇E*a" Z ӹPEp!rBFK Uܢ ~I~}mkemEIK4YӰ.Nv"Zs"D/~xe)l;WlB?`enj9eG% e?u9s[F~?00,srR:OQa݋sC)!H4H7V' a5.rZ =8VH` B, VrgEP]ru~XU=ZeioNGa˷veVְq"ҊP伦v؏jH4 7#`ZksΗe!xqC] % DIª<׶;O\3A^^p]-'{~YM8!jy7M-$%1@ `CH`0uw+ߛuEA9|sDD&h02AG|nh {52ԒratʸDfku JrZ'?tI_>a]uԹֳEΆcUcea_Y9{?ʆ| pSNB,|p0j] Ʊ1#nJ lInM"`x T]{wW*n ᙪ=å=\&}1[jXe dM-q&O8WQ`As3rȀE+thߚ-d}=tݾgxx<06 b$.՞~JM b1Mʄq&Kձ}ߪ{4D CpԤ`$n9ل8$ZuQ+Vu"cx>3Ĥ Ep6ȎM͐$0)#L[Qܐzce,  ACiA`񮲎ZY ,FycMSZF2h8WQxOfM0SbrdTb&VIi鸻kse$1 oNT,GѲbP$Y$qCF lߩ,K"V;+_K9\ v]sHe#3 Gq0`Y5.H4,xU- a c9 Ë AQzǦy,d"fU TJ5BJb-U`#2gIRGfR*aE%J,HjlKi)GO1^yJDٕnC2v2So:_eIH(Cv^%Z =qN-EެhZ S;oܻmuLP$p!j(.|J 2B$9z1!H3%h`&k(;Rۘ/`}fZf P 4KX & V_#aK ,//Qiu $"UM󃄻R/$atI:dazZ.(!J u2H`+C@[Wf| n#@pg6V Hp?Y!\V־;B9t>1s:زL>BlyqȎ0C4$f(#d4ԜH~ &2G a2q ?R:*v},/}uȿh`oyJET6PcU:!&33}SV0xh277kȪA{  -ב}wS(QQ$ B"-O+ೆ e*JTM-{Jwl#B.SkqO;'X xAf1T0f,VlQS/Qe@mh.Iؒ*i)CNT6wywS,ݍ0ކZBp08;7B1v" qfC:ZrJ[0;Wv=nX?v #;*CӮj̷Ho}8"-v C>sUpҤwg.|3Ŏ 5Ed[~nc18IJk f6V@CQUy%bUB@u;BqD2@2lhp&AB/A vl"%ؓ#| H`K*?phOP<\wǎ<+!r ]c[W~u[eedynNl~'sw=` 9?`qw$Mǹ] *>Ü#K(G0h\n-'`qYOAÜg%W"BeC<,OxdFhyhk.wݵ[^~}يOFUQU"݅L rE`]>!H}꠪E ]dpꩪ Yȼunsh8ld Ҵ]Om,tluTlY>" ‘ Y&;G 5L,Qti^|HV6NTD󃸺0 ϥVu"ܦ$cR+  Zl7JK%I !t_Q.WUXYյ;.(UYN%rNLCx5# R!Kק[^@+k>DB4h30VӁ!Ԑ~g5JR+tdIXн[iݘ#P!A[vƹKhc-' yG e[9Fф Fuҿh1jD9۲:lj j`˒'4$vɿ O3ӫv$Mgf`pޟFF{(5Ј 7xoNA7_c\aOVq-v74uT=kk$vmw6򭭍SWmJ4<*f`РbBx7DIz>oKvo>J?0̣2%A ')Ptn; {`G̢NtIB(,H#;#HQ`nϟs[B&:ZeFj#`C1y%g·yC]];8h<|R htOw;;As3KdI20c à%y ֤8 |k1%g,k@K+l PGXDCnߏBܰK=z)괇pyq}sGW7xephI?!-Y֔]iՕ.ODdVf !  0XGnc$40#TS$[uz\? 22mkmv$@MUARIYSFy?Nũ1e ( ߪUsb<_|{M40{w%9x ?ѥx`78,5!ܖNL!6G@44RleOEO^He>Ă;fY`% ,2Pd/BP70ZBbSHdw%G<].JK |NIlH(R$_vh!oiPSi3=ur#s/\*퐟-6ĻA^x~4p/ H;y% % lY'>}E&*@DɗXfHrM=A|״¤YF2CM$IˀN|؀$=7uj7W>XfD#f,W`Ax5~HxBwuBիC! H o'VGBH% ;dHP) !,S@4$ "낼ۮ^,iCctĴ̀20Crz~4û^s,Y:L+aƄ; CuԴλJbsDЃϿyOӋPS&lRCbPEW)a=Px4myU43@WՐ 1BmfD(h4O Ƹ0gTH C zl eTdd 2Y"ܫ2D91&+H`)Gf_7IR Ae7AHZV=~Bf rB̺R̉[陎D…P> .tajܲ^rf]ڤA@ޏ8grm]^7W nJ2?fz~`|J F O'!7C'6! yC2[41|"!ƂGm#J3+Dš78,_kJկ`\xB$B8ka$ ]`Ih-i !y֐"F`G*ɤM+\s9IQf`|Nϻ~{e;&b$B=1H%2!o՟[D|cG!"J~qaŪ>Hy 1>msv*6xR~ qB"z!Cf]NmZ5'⑆z^tԐMTI]>U&e0PV!ӊm~tr B2D)}v#1suOgnH,o=&Hu҂C[rNnz77' ,i{ldً(-B !:)+a<>qICӽN/:A "  Sm-l:ZZæ_CzaȲą'"/4"ĆxtmGoC~iGu:8B,ul5(ER3rgO=l$9kJ5viy9}sa-@j;ccpo'b&PD% xDHjH!& |Aܪ)CLb,4hk)jx4%YH-" Qke_AX.IB qT,xpVK7pX-m9~-Ck7Z)ĦU"Tcs|B5+U3{ BMkI0ܮ .U8BHM;ߝ>?o% ].綎UcQ6k,)i14.1VǥۋN`v^xc&JqwDr|v$?y@w|9zҧڣJINt<=_dK|8w΍s̙=kYb!ƃ+8{o}sl,6]`{#bÝQ tw@zQj1zXVwӫ3warmty{{fwԔ9ȷdy: aTl[oB2"I( Nb)>Axb x9ee)$H&4R0hA<PC)$4Z#+i lc*B"FUZQ9Дhnpy.|"qUՅsm"Uls1!CyÁfZK> !K(>_NN0X&7T0# ~ϚC^әvY9|W`/N!@*;Ũ!B)JY'W[KI-Sfј*&HUG1 sKF?i[\(s5B[bnXh48ܺWG@j7-y}DSÿ́K"Qbg^, YCr\ysݏ0>a=NR@yswvG?ZaHCKbi`oۺ"ė4^|ѥ.4pe Yal[K !`. ɕ5lV%<'X Eܹͩo^ķSer z ڶ|\6o@>QRIҖ:`vk'FDl+Bc^$[ʻw?jGKCJkW=ytF!tbhk4UZxs=s;rpcgׄUm<+vbaHU9 dҼ53֘id[ !M$XCͮThbxOP@dsj 2wfs}H:7ɡoc2aHYowTGhǙeDZkrqp܆C<_ztKɉML,NTWtE)/dᣚGbw6UӮMϵ-1|IMsNBǔhh=_RRl"-+̐~Dy^)5.ر$bRE9ZNA?uXڍ/|Ӈu)9/91JŰϰN*0 ax!%1U>PE(no,X^“hGg56{P/EOѶh.ꖃ!-_(m-!-!o+CXks.}]([Z!)ذ($7k۶) B u]r8ݾenjKɦ& mD'ިV2%)W8qi!KPzZq o48 /6& P76hsE`L)PH\ \IagcU R7@̐V`BwkQy(0}RWz-qĆZ B^ nDUļ҅s+ w*7%~Q Y?յ@S_jJ`$"n?hV7P0kH@VZQ4&_T,i M4̳3u\3hSUmH+6 0+Cx%Xb"~rj_)ˊH^1Wrzdp oZ[SuK T B6 Ai!~ՎŸjA-o[ivu쳗j7ip&^B42͓4 Ӌl9Ovo:!2C>UQ϶HEfH02HL@t % IxCߤ"t[!LwOEB+-p ?Egk&Tr8kY:P4Dj ˣ1̡Vlsai'! HM$@) Ɖss«HLfKGS[="Qd 7)Z =d<7 +U}ig{bɟ~%.u9CB**x7u oSP:V:Y%bC$OK~\aBF* 4Pސ$6|ޚ}v i'3 A[A0)>n@m-{\^FҒR Lȷ2m8ك! ` !hHbk֭\J8[rU0?GmT@EB_UOGyN zJ==PzܿN/R+gZTdB'ac EV(6QY6if \:h$ RfX + >/-m-p EcH0H26 |{{~T?#yPuKoΫ-﷡l qM]W?X'=/ǓNPO'ZMcテ7K& DlpG(!Xf2Q/KD 4i~;5AϓT3u2A9e;zz2blaBLE9HUi-7 !7Jn`ibpP !7 &r|!LG-ͷP_Fon[(@Sb 'L ިV_5 01xGFcASѱ948p 6\%8uz8w@7s'<^`\kg)0a1죓L2%ɫہ! )XK~69](e[/n,wvg1xϋ^BMD{ wv>DtT0>EfHxͪ2BqsimwK|V86BAIÕ 9YdT-8iv|3pn1{(Jsئz21@wםޖt`!"!;-9!Jc-ScOd3S5.B:Nyf2yCS}1'@:wMRsPv$NE45946e@վ/J+Fߜ"g@UҴ?ڧH0fMDӅW[> M{fJҲ&[W N l7w" cRAӈaX["EyXxz`>R $MB#{\WPX 2(>o7W,~G sUwޖY+Dmf~vX.9{0~2 U$x0n6t]C*>bOb t1ݠC3ISZA] csyi,SQɞ8IS1}қZ=aZwW&"v]3yP4MV Lb|sm& y^tL^V#\Or i- FPa쳬}u`AW0CI-߳y4U;dawuso۵+"S,9i cg7 ?4M8dZpVAֶ({Ï\7RN^?#|T’Ej˟7@zAx<ƈ:_F" o[92kJJ=AHÞ@J IDAT}7B2wCAIà> Dw8[*me !JEg>[*3L/O7PAپ~i}Ӎōza o LC훝\ؠY@0E`|4`0p`3,ߵ2-RPkYKxj,ii{1>U2YjUZĂL1{Xæ˒PBE!jgșO!Gr GuCᨴ~t O kJ?V1.~OH$BMf}UBH٤VFUu,򘜲Ulz>Ze%cQ/l 4@b$Y@ecvg@eXO% o1b)R"'iFfm# >mU Vf!WDfsn|Kk7"HTCg,o)9H .f!=2+-Ӆ^w£~2> ;=4:{0NBN% 7`246q [a͎4F@޿̐pHؠ(Wf @ ,iy!>hNrz=Oޏ i#3H4#3Dx4DC8#LqV7@p;$x&E6A [-ȗ@̫<xu䀘̓=΁vVGs { nfY~z_l}l<i2 N)G-Kl"`et JzauaӤ2-'"raF A Z#6d@W;BFWVEQ"&! 0!e-ke AWlb1l.*SA\`"~_N~^+*$-=4&@ĞpE;᧖.P #bˢbm|;H]#%}OXkh@?oJIb Vf0*m a-3|*M;z=?hMj hhH>a0 bh5<޳#!SZp`_]ڵ% ?&EX,@2}4y=%63@NƄ;0A!vCGiI %mA\EBЉա*y^3S+>\[הt@xC a@A ҂+6Mjhrm*j&^Lʹ4B w|uq"e xcD3A0iwp3`knT46A&›CZ6 |vIDK 2P[A4GqB`* (A$dR;BF0>P5晝}Z`V;֔t`*J aBpaBMi{NXM44pbj\.8F#Sف" Lp E6  Ʊ+M2'2P\" ] 4Cd -K;Iϼ2F%tb ix0K`q 4Cl@'kr#ݥi4$ADGohྊ;b !2M>w#uzWժ̐<0A@H&"Yh<MKhGVf I,Z %hԦqo\4ƒ.T"tm-!0>Tl`/ W**xVv!N 54@ŲE66Zn#i e[]:= r L$6cx+9y%yN8QT7АPc"6TQ~I* O}|T&Dwazv_ԋl Ī,|ghdV8#>X)5:ȴj d$8~^m&NϿc a[m E2PCɘHZ|%̐p8j}(ȯ-Hɹ@^P[ (A/O,̵}4, %]XOtǬ}"iJC/+ZA\P J ͒K ? L<g!>d@p.AQSأqr}EEY}4S`ŝfVs6IR!8]`s@dV.O5}L1 ɩC( 1,]8P5tA!\>K=j="Q.iuٯmMbAC , |L}%Ǝn(8ۑ>6 LK wF=/])OSgaY{pȦBHpЅV)]'*Pcek=) bKp{d:\m;-'ŸcE"d=RD)Nq2$L`HQf A2C)0@D2<Ve.Qσ od?F{̐WXN"8`ǻW)ٰ$lVוt> Cb'ItLrB" Y+'t^14tǷ8Sl&ۥb3-c )+3T0>h(BfDCGÞ=yt<^m\(&8ع=ҹTSUEY=Cq0WUG1*m8wmZZW#Vj" ou @8_U*2X\%F,UUQLV ]x2a,aj+r =, d !ۑU|IC&\Aa豗ϗ ں 2R[+;x1#D zw[`q&w$ZcsmpE6K,wJ\@dhzOlG#:hHA-4`S.Aø#qDŽy7i) FpZ?YEYy\P6w.w[| {DD_7VV%;dY=p-5R3@OÂ\;ցChb$tK0e1FDf;r/֐tr ?Ʃ0!Ac9Flw2]7?ƻ $&4 1r 1I(Q$;֪4swZ0;0',K`A+G9ue0 r:/j`/RcMRg/ԤiM,xcZ(7n"yLFΡN`ƽX]pFM+ .d1ō2DiAήOrO65754,ih ܆Ae66;ύz:Vf4u<٨ف" L LHL8 x3.iԌ\e&aHE@_RTQ~vSᓠ dTէ6M 2=%p/0LGO+.JMdB} "ֹn 6u`y+6# K?ز% ~W;F0>3 Ɣ[K\LvKZ` Ry2G7) \. 5;"f&xD-\i0| R06wg\L{`7ii#kcjt>BRn,C3q+? ZPɖtЅϛs[NnG5O3*SLőWɂceHJV,I ^*pK$/s-" r~\4 8Juۓ7Ҵ6wSs-/z#nՌ[ws=Rn3b~&R~ =6 =-7k3m&JecBr`"LUh]]"*>b ٔYͨq~^ @)-Š=YZsO6t#=#r>Y:|$ɉV?瘝kov>B4Đ z~0tL/UfpÖ{ewAp前zLEf92-繷 Z r]ٹ{=myA-m)7O?a&O%9 $A* O뷱@:|{l +-߾r #3D=ۦy)1>A J[ע\")ނa$Y pc2H o"4tJ,&JCzp-ؒW vY${U,,5YŹmbbȲ[T(7E% ll!3$[7HH+3s'ޝю}]oro0?33{ yH+0.'/qeS "RF‡;Ih[CP(|v/@z'%ڠG1& ɇ~LۭPY{zKq̰@Q\?2J:z'6"]~LS"uJ~S-ƍ9dcK$[1G0I(uM x2xo|lÞbiP@Ă~eJ(KݳQ程(3!hS F'[q `>Rn<4m4׸FKnBty U;~u t3;zgwH4LV[UyYuJH9L;5x|tCo^Tv1>l(e1o =cgh /MZM;a?_8żp L#w% |մq|.z#,#zn9˚N6m6 )/RS^ nP3|*|oK,i^MUy[rc/ i.SwLf{QZ@Q?inCl-B&)ٞܭ )q_~w_`0O8J9Bæ4/UEZe q#QJ>$46-@_L3dXů5pK P * $61m|TMV@?z[:<؛c:(o[Zٝ}%od0geisO׸pK YRI!2,r[ԎɎރm3bRI`8ɇ ~}"!*s*B\ϧDwCyEWE=jwaٹdz\\K3٨ͭSk Eyʮؠ^nnu+ nTUG׷6㪢 t {}*3`Kކ<*ubGbO *MXmɭPUi Qm6pÈːᏚfohe jvXpȴnP3ZIl|\kKc5xiofK'8b0kP[3YV5L`O:!#X[]L#LΩP]TL"oޖ/]i*8޳PbC |䋙Z>[:_sMFY`leM*ƫƾ>) qJϙl ( h*p< 1&2^$'3,"& IDAT1lq'0M=ˬ !4 "}YaW gM{T'v4SZ-kᥱ CV ?in'|ō>j/_lU>W)8i,8q:dT|stiZ6.,b>aT!M1ߜ4$?SLc"T; za! UTj9oЧRJؤlmMtD&n`@ӂ?=5llZ I`F`/ثF,i8͌:P,j`S|C^Vmi?b!!rbvzkǁNcд~0>c81q^VL1ye؍BJJ_5 J#׏s<wC u>Tl L[7 <]J}l+) _ri(1&IN0Vjſ*ȠoTf[(*iPBp[@M7gbJz6M kvI-q+쓵cDdЄƮY- 5+ RLcZd0#*|ذϲZ|sܧ4O <% 䃲j3-CVe8ඩ' p0&̮gؠO` 1} ƞW-.+_.hhS\X'JEB&m=+-,:(FEdf׃^ ,A4í5,i8 0@dM7C]+C@2DU7Ofi~x^ؼ beH.`~8쓬c-OfAL "j:gbpH\T`%W^Q~6ub>BH`p L8J`",W`ߥ_a~LDDcO+G2P0$)2C+0MU W"&(K"3HLc Lmf 8űкqЈ$3\i9#Op+3,Hzfhܠ63G<\gӀzi@HK4aqm/+23Q@d8excP 1!MPc` .0Pxv ñZ@9r% pax L|G_äN@ 2A#!\aGxS \M" '˅uzWX:64_V0pcLma)KY`k2O!8]sPȥPI"Mf X(` ~V) sf>1, zGD₤ߔ/< VNaΡWA uzӒ,o0c[oVxnX!!o^n T9AӤǬq"'bynhpv $) ; JWQzaCH\ ^}GD$CCADhLD_p&jXpIX79o 0}7}iaT6TVy1HT9M+ĦKܪՉL&8SxH#2ði[>" 9 xCP@b H^(3x,d&xXO86*e s!2!֘VM̨Me&mJNAK=̐Ubegi R~\1l 0C"L49[tZYlAX?One T1̓5Պk7?Rnq,&8-p֫&؟1ɳ+4-=9L)fW^`漬p, % )` a8@B`cr t!<5DZɁs'ft z`z؁ ߇WR"2}p4S 3å(S爴G=EO>HܛF b LD:鄲(h!ǿJ-Z5^x'rcCVXh 5~=YcȈdIMj3ቊ4K4!@! g pA]0 b)O HO`|HAjd 32!v`b\{ Zq7f#̏؁ j~e~+@Ae` EP{S>Mip2. 1q HF#$ nJ( /8qxkex`p2C#E @t uz'M!:1x7lYVh/cp  "-1uA =Ich߰70@x>60qHD9RܗeeGJ\ki u!"0(*Gy43@Ivq u<\ΧX4? LPlqV0keM,[f͏x#&.eWG}84M[.37uܗXHlzztqAFOCk{Sk >;FP)r,CBDZed`U#CN%8DpP˨GD! 0CR Zȱ `eĒ#Z!%8"LI/v Y%95ͅƔH4n JQn)!O[ Mp yƞjFK}zr/nRaldZ* \dϢѧ4 ` 3"wIb`"L@zM,&IHx[E.MLfʰRUr n+Ǻ7@ Sah$36vn?]=SM,#ݒ )HJR_삝nH@D`"L&5g}yUQHy~1G}!CU0WY,̠vn?[ۅn`"Ԋ&fjEC%π V o̝-t[:qbn4 !~+koKfUuch=wg5]izjbbISGoåyqs;2Tuiޢ,DA1|AGo%HC0d k53X(uąd00qn; B}ox6*Me'i^!x=0WeL֮kZA{}N{͹swhӲFO -fpcq_3}-Ep4 8  ^{G p|b'hۋ;;5"?gϞ,WA˄I%M06F,2oz?li4$-pil-DYkA -3veVjƧ-K,GZ(WtZ^?u1Y%aa,W[2l>:?4Eeːr]<}g dYЖm?:>FC*>:u-63iDimfgG6d+uY 44T`IJYsii}Aש*n% "Ag-J񆆐xpdH d40*BM46oÉg*k5m̴WJW` 5EΉŪfZ}s{*M;4 G=`CvTMI6:_T>ېa a|cњk5W&&?`ðe}}֬C ;NQVf3o,Kˀ\;w&sCFG32epȴd|`ZͲ:>v5Bjڰa\j`YOH\(N8&w~Sk& jar_nRF[iO&ƿP{[mʒX+mz!2QsYdSUi82)â(jbz}.]x4Ppm>vvRpm3X:c.2{ٵi`Fz-]TDt1a/kG[U,L-n2rx9, YG /^:Ua|ԜxвV9N*;04ͻwLX-)=Kd{%cLuYĒM06zȲΥ.<5w/$x5Z2r! $qдnTw`rmF1_09kaV@8b+C7<)AP!Ӻ@j#}6BbmwcO҇[:Herny/UFTvݬ*,)=~ϵFhռCFA{pcD-LUG9XAjEc=p# adŁKL>/c7ˡINMLF(7(ꮯʚE]`4) ;H7.4Yd0a~4?pVV9 ƴf <+Oz- kOhT0&Ӑ%uSUD=W}w8&\pˌa{w~;;bZoei(:7]/<` 1QE(Cv {{7 țHCT>]WX?oR-lUratJv)gQA[6mf:Ibe}]Hdqج!}Cf]ea}Cf8'kt Ae$Wv|زŶ,*)#/OT_q\Bp14xV 2x`Ć\4$C !!3f׻/~2ky<2;0LXٴJZ2CGS#01*+2`ci1=.3 wQ% FεP.#}w_dPI XM2C8v3H23>%90AAmK5IqPArp ӓIP"ݳg% b{9e0p,ygeIæ ]Эg6z2F -4- 2ؤ}ח`eC#r ~hJ L@ JQ@da/cHt2JΨDZAܪ.+;=c[2s?l3Hæ&~%)GtwgSPq&}9!^24|!z0MD@3 A2c+eCL3#Br@(sr l.ilt vD3%KCf bf>hTp2G[Z Tݗc;a~g|moM[N"e]vѓ 1 6XAtKxHu41+Q%2}bZAI9cKuf4Zpl؎1 Ill4Іvi鮺vܮkyxxF=ޮ{}__switś.aH0Ҁ:0(|`˜zF }D2ZW(FBb8˜g6Ie- Lo_|=/=v**1R|nSwE9 !1Հ ,?)e(`k9FeHIK5BR، ~``N䈔%1Tf IDAT0!BM-eܥi'KMH@R LܑwnN%c鵲Ҙ*>ܖM"@Do#7߿i++i0a@oZw0֯qSy٩i)1qٶ1"xA0Wi$J`10s`]%cی#qm¤ADLY~slLeMK>n`"?g/M]fHz +×}O80*?&o{csyD$i O% X+0>;T&|aS^&VIn1&' (MUq1!]jUIא~#wp_z"+WWj+cSwZRIwmNV4Lx{1T·ֶ& T[|acQCh9Frllz)] ) kڨĊ/#+X&^;D/ڹg ndY6qeيRnͨ\kL5IS'|wa@CY'pXrVߚ %?Gg)Ke{W2u1JU(S v0ٸ:t sCDCkߐ"Yy)%)*X>u eu$;O"Sc$g S$> !%es`Tvmq_pNa>3wZPH> z: pն$7'TBިmMz][pQ|fjd}mqWx#EַǏye舾_); yHQF3ي,]ۭьڃMaVc:}!Fyҭ( ̩(FdJB .ͨRC:V`_9ߌ#b#xi RQ D$&::%#/7n7y7gMrI08{bz9ޡL4o'AP%h/^":=f8S35,iq FF:șv'+Cw@#. "+um6n5#C0Ef}pdžՖҋ%%qNň1+7;3%+vԵE cwXe0ͨDnwlXm5a qNs FF ᩚwlmI.9Q`F%( i kUb ŝ4+$?sya@`1axS4+!-xD1eKk{AA! 'ob@`Q'ٚLU).p$ܶ}o ׵HPRfi?!\ iG N,Z)ֺ֩$:,ҍ цqͨ8i0*;]׾$YvI2{P6\fphF ̶)ϖ={(#z ##A|\*9xa|VJ % &%\JZ:o3eKQv076Ѷߦ dPN罌v`q D|JDsd&RsŤ猟C6߹a;i9~(?Q^졜{"iƍDv++4{J;T]xQ.`s֯p 8Wu!!orH.ϭv4~J7~FZ"ӝV}g>|2Sei1k`Hikd66+]I_ ~/RF`D~4Z/ -| #فm~Xfgф\agٿiS ? *]9Z0!7/N3jŕ$Pl\'0wtwMWVdX0PR]@$eT` 2< 2H\+HP}Wl:8l떏_k:M8[Ȃ|6|]B[x IRFNũ_$Z&KI%@>=M7Nly,M)ZD+r Nnث5*1;@]0C=K\(C[ys6SYN)|mNeS%iDdG!0')ۣi[Te83E X=vq,m.&4΂u {4c9Fcp82hVO XPC !^B=To]u {4CE{YHw뛘Y0΂w`TܭL^"Wv,?Tn_44lZ_*UqlY8Xɳ &]G;H)cYH^.=d$w2A`ʖ%C} EU;Sgnx$.&L{~i1 e~,ZK%7˴qP,da(K N/g!p$@YlC9R-0\| NXV$sWj^ȑK6{_oK ʒ^G%]ĺWYxϫ}%/0ť1K8G̏,)~ qydIzz{^k澍kVQy]o<^;(KvBKd"Nı[% [R!`l J2r Pb"<{ۢS+,: #Z7񥍸lʒԁ5NR0GI%na *koK,8R-]ʒ xq>qm䄠$CYܤR.uw2?)d)/)ty_>G=9\wQz]d"nZG|Ιb=u/X$*V[9<^' Ò:G I $Eӊ$+8F9셱-z$:N?aHP4,x=<؀mMi]LNv'+Xe $iQ;(exbmUyU/y|"5m߫L. knQ=Go)jyأi,/)V08es&"No8䄲f "\/nX5Tpٚ& & <Ej^H$)#I[svoے6-v=9[?ZoRn1q'lVQ io|)G.rۨWbqQd(K =Fi '<|\x_x7),C9h Hz*5E@o ,?p#/Դ4F744Js NUD%W)r48h}uZXHÅ\#ˀ cbT( ,$Rߩ*ث-"n!E>a'IY܅>8q})y3 Gj!ur+d &Ȋ$Me,RJ Û]f2aaկiS%#w8m" f7) S^Zu8'vG(&8v e37%.LOTTRWd_fIlL ]Vp)KYK 2tYB'8/3`C=|X ߳aUzx6\`N1k1nRĆkEefz5RNYѣ"OL ~WzX9P8ĆX{`kb8Iه7M,-VhIĀC,!ES;o}DVb?/#?%Dذ9 mVz.y).0oZvJ$:JMhP>4`DICHx$n[UiRRUJ^ъ g+*78(^ >]}#JM]KQX$[XCZ,!-~oEg/$Gg y`H{4H݅& AH\ ;%!0t4@xH☦iUܦ*L/%ib@>ɼR.Ѳtx*sDl}(q 87?NKE"ufҲxa %{UuF6b]d:L$x Uw_ֶS: o0Bu:7f0vk^b,epR *lfd^۪fWf~j_1_) ;Nٔ2 EK^eH?a~~]ʁ"8d!,2#^ǎIŏU 棖Da]hܴ:g!n="PD7o0B)m7s߰2.Zs[7A |#~b.z I0b\~)̔-U;N=JDүe{+XmћE OGޢ7g _Nl]}´`bqφ/Hxn;<~oUNYn9}!( 1 /cPclY6K޶Hx?o;M^:H锈6$ѯiW*rD%~W*2klJ!zu\ƗS!lJSO'e1$OΗ݌d eQT6,xc|X:0pFL%.I@ $@M,t"*Prԁ,aD!u."0p 6f gÊ,pGnAE٣iG7SwӺӍ61a{]f@L&'UA:opJvh'!M oiyʊO!1oZp"9¶\5 wb׌]1gB!F{$Q $.M\fe8b_pAJIi{3QuM\`~MB Nl0BS5M >X^k0pQ*Wt9H&:L#Nct 3$]0rA I7kkzy(QO"_O|umq(ܱILimsz}NԂkk"ᐳ:`.n[_0-YzOpb$nX1կyyLn0-Z!ګ lw&'x[0Pnщ ! IpWysv21ĐeIgfwr'C7i$``GEbߩRCߘxC¬M Iyt!D1yl~@ K1a1s1Aʯ pM$?%0Wx2EY/Wh^z:ܹ9-*+ &+*^Lf3k::` R퍋ndlZS̡ E+ľS-GL Cp1$a3kI7Ut&_(quJLٰ/-c~TMdK`$^l\tak}8Mw%\^H^j $I_[qg :l4Nt?j^w}%{v(0j)7u>~S㕭n3V/r؎a.k.8*R۞,^ZjY;kH m2 oD 6Y%.`Wnn^Ip$Yj{LeMqc$0xH„V+~_i,1|+%@QnO~lf!iwb ׋ŕ7oŜg^Sտ|]:17u>~e2:G 7-p^ۣbr`EfvMMb ,̃e2ta}>XK\ԁs$!np`- IDn{u"\&x4Ћ1 HH ( 3=3먾%wK$ɉ49ibm*[qw `P)u(pX`DN,1~s^ۣbrMߌdH6-`6^%4t#(x[x_I! DLļʨíJ\lն?:cs5GbJeeJKs,crlR jO5G fɾWtB0E\~;[kdH |&Q.W ϲޯ?T*E1:t۞ t"&.=J$InǛR0<U>P"p%(0ǏD}=.Bn1EyQ!vXO zD:0cHi@9y)riJxAxVc&I[EKe|ӳ\kY,f,lYy8w8Ӽc(Rw- +kxnQyZ*i9"c%Hxip_}WzU }.-~5X%ªoe܏_\CD0)n\ IDATUMb%c}l5ʧDt@ W&ij{tQ!q$tweJ4xq2̏^Ed#Ltaoq"BP A4?/}7\i^`c-yt_'u7ҘFHyvneX o[Vo{$Pz!ʧP>-{ݸWhk \|0Dg y@d 9Qi-W>,WخjS{]Ӵ+**TUmϡxDAf# %-E4;eC cP:X2Y6#Lt~}@PI폾";o?x-,cVV]FEgS`+6'xSX b /ն͐=Ee$|lt%8ʧÉkH.@M97iEh]UdLY~8`4!Nt!BOaQ*[j=~fu,cTu>3Qr&|P~U E8m,I웑 c=AزX"8CKl@! lϫyCs^Fs$YMo:Tov&K j'xj[g^L@2/Wȹ-36p$M]CυZܟfS~h+l ߪ[%Zgg#Ȓ-]#*E&?:o4-|fWrowܻaK6mKbHӢ, Q)á(Ft=y$I4m|~{8!O06M:'~JHR,Ml]WF9/ 02DڑW\ΫT\ɼؙ~@.w(;BUѱ7kh.+sDm?̠շET 4Z3- _ΏZy͜XUvE `J£p}~,$L]`,[k[o(cZW/2,$jE#4m$Mj]Wx΂Grm 1+I~6٢(0X^\,/l~)ޣQHXD-KnTF [^UA0'tI $R(s6& $whyn\ŁdԳs[m2?N&R$alKNu9ku{5%!wc|dܗG)=ZWkMk\lJޢtV.Ht,Y |I0 r`BvU 8P`\*.08۴ VYwb(NUGP}[߻ z${2 @ v*_6*Ib 5L e<c$K8K% ദдN̖ɒ`D^ &%8"`;~% "ʽ3h _5o=<8tDG=]pQ?_фpp?w(AQT v{חx[ 7 t5`Ѕ;4^/E+0Zb`8߸eN^!uثѻ76֐kT@*e M,YX6`mU[G|p‹}@lJ21;BPZijk.0jWz\OrR-yu4vN*YڕWߢ"e)pD`I &18V (-,'~hC\[ߝ]vpߔk闋NQ @!=bOɫ<v12QJ w=,/`uF_xl,!&i ψqYtCi) >JmOņbEa65/*5^KyxPiG\xfٗ@o0C޴[b:rOsԴ/VdD`p?12Gp0qŊ7c.Vјvq;'0\END>[U>8_]ι^U2' 2 .-]ۗxp8lhwfn~sNGܻ(-K'I ;>J o*K}a{c&$#WxR.S/ݴmS/vk<6, @q_=hAxPS"Ɉ3aS*#0<1d՟e T\6p>qB9R<n/dI8i5M5o8%01NjE$y=Xw wB4b܇AkЋ2 `WTƵO9CЅŸ{ AxĀj\B٣I9$x ]}7a87Co&FAv ;y7ˀo7c QqЍWKH$bIB0D q/nңE\Yt>1O_ 8/D 죴9LƠ ;4J}k! =VLf2}'% `9nd8*h2*j$޴!8d ; ϒyF!J ̏M2$de8X! ?r` \`D-$ʂ E#V}Eb +{{X3:0 qigWQ4Q&66mtC.0%TK:X}! x!jN=Cq4d &_#\`pR.0IDŽf5$ջx/]01|ߖ<„$+n`J  b2+d\PU >Y]1Zq>t0)NlnsK/x O!Zd_AmY$THþ`?u/ MTbpGXD\qR.0X ~ýZI G`8P><&@N1AdI=*r H!Pp8ؾ>/uGâL %%$ٱGmK>op4O]^@{ .+#o\)vXxp<7yZ!2@ޡTWod9 k,0gTiDkS뀟ox63ZYBDBJ.0HM)>5 fQ! mEOjcBh1qFoC͏~kڥ UQע6v t_=qV/)3Jt( ZK Lw>cK S0]Q$.:vm&4cM0y;CHгk=!z6$4W(Y{>qWOr B֦W0Xqft=aTRZp\08\mR#3L#L/-}Srw6x ޳ߖ *k v:L} *7%1s7S cte:QmQiɇ$Z61A3ˢEQ O"Y K}oAZaBIgaK4V7 ,/M||F9yzg3!7`uVshx˫vc5h۾kd yҗM6#\}=G \׷Ηpӕ{wMRHdu!e4IДk2.# "NJ_1ba2Cec BZ^Zy]Zm^Ϋ-%v&|޽ٕߋxf@QK Kflx*B0CU/i@t˵m< &HXCGNak֯^滌:k-, aJm8ŘьjN,r;!chXxÂ'"!BQ0`Pi֠LfDlk3iP7iy˫'[ 5tA,VfwmF N.>2CЍ6|m-pӻ$J N!9رka~M:оZib[ӪڲX}^Yq(aexM-G 6-*** ٪&#ͨ+_S`'0Dm'C =9A(08%U#`5H͏2ID(:dIpt^$3qEX s,#ba|Ww=ɬuJrb V@ Œ~ `Obk<[3k O[x_cTwFᑗl9Ҍ޽,0$= $ ӷ|BX&$"Q"8B1] t$ ֩۹`e}mc%dOQf,8B\(4m{$-0]=O5>pўܾL 4Ey3%k͡;bC0z]Qddl"#ܼ8Tk;"8D*0/o'YIrbO*!$!y=x`Q>n״|՝ "Bsogw,sXC<I62 'G3up8*nJAl4ӿ/״!3HA W0]dRV~ϛ2qi!% _r K7x3(,# %a#H4c,݌ ="\`YhY Hzn|I4 6-(FAhxD 3*X%pPbÕ2HbE4ȲtZ&kALLj.8,[uJy=USc*i$X  *-ħ'Kdl}%Gc˂7дc$bru*L.dĠ  2a >i^'tqⳭEΖ. knzkL{7 Gy;|{xNbϣ-IC9$831xdD2rCȖ{U.L)&@ߝݣPQQ1ot $ݪiSFk!xc+|aj{N|+WDBgHx\j "~ϫ %x˧>޲26q3Ƶ=*\&66'[xĽV' .HGҤJY.0 k%fXV$51$_#ryᾪ*gcq"ON$(>:!5.t`1[Je[]_rym;Q@QJd;qKH7cY+,HaAhZю͋k$IA_#Y#P]gϞhZ8No:eGp0.4? " JD(:?W6}*-D$&Hem'Jˤ|LQ R[Ctdta8By!0Qey~g>(v!C! q{9+]i}|^"Pmi1ՄӔ^(F:Ή΃ [e< K<& TNoQZ)\A]39lG'+a"Y)$8b! /V`tj{dy^ !s"le(5_Hwi㉡}YBIs_p wdx,[oӼ1Nb>o$m P>֤ҐŃ& ߮m-eY&Ex =rE%5݅/fTږl^>!07@`#o$ $ $ e(Qp8Tr) ,-xIt LD5>[.>zOL;܅>-KϜ}zT L4 n(q_oƥ.&?ɩ_@ﳾ|`f_+ͫ'B1[V.hw!("#aYL@gbYu˹Š_ֶ7J* (`k{I?kT<21Ī(WO*Jzt2  u!ΗEH La (x$ ~&WϿEew| ;$?n^όxk˗xI`΂5 yNjEvB܅XP0gr"5- Q{aµz y+ 6|2yݮI,B^L Iʡ>Q| >lm$i?XH"!Bi[IfFz% AM @swȮ^Y8) PQY`=L7i]6HUđ.OC%8߫[pk6# "]]Ӷu}" }pgĆo׶LRgr/{>O I|;|0-0&\҃]x> ?k!+w0n%5 IpؚR4(n{,O(*ӅWk79:M2!3'9s8u0]W\פ@L[1B"^B ɒbEWW &J깯:~4xCI D-6ϗH l !?J;j6`][>Y&lY>e.p!d36v8EYZ5|0X_A1BG5 ] akbH+r+@Yz4?&L_I)[]ddO];#%8LV+ 3Exk4a[KT5EzrD 16XP}{lqA =ŖUŅI̟~xί~C;Mt& x`.ܻq#Ba#_4X+f `+rz:(,fݚQ 6ϱ k>XI:DY^˟b,[3j$|gh1Uppn[=Z1|n=v qc\ ykVҰi1/`Gl4~]GIpI2P2܉4\ K5S.m'0+*F,@^kzF/zjOCLJ2KWd1aL7!~Ȇ/}~ܛbJ:'Je}Cc$Yo;1@JaT-7ҨNַϐsy+2t0w710#{?k$. (Q>/ƍZh34?D4/&/频.0UopuE_c>!, AL?jX P5w6zcV? ^aQྞNx'I ; %DkKtX؎mMy .jG2VD8]`cNnKDJܻUq@$cVy*e` \`=9]pn/ڧ+hycw*DHRVc,71\ !ZXu\H~[z[&S#]YKJPq=jAaTcg$TU9aJBLW7nۯRѲ|@UY ̔Mهe,ٵäƎ eخZV<9jxY˚64AwjE"wp}EaNgX% ˂W+'MnI%jNy6 4MEN?~C&H^GUoftε)X>ܑG/0.l編-vHC` u}+'pi͙Aڮ{VtNt2NH̫? D "] uF'zK B҅3k!0Fu2 cTsu+0VۺOg{''(P1Mإ2Ⱦv5cu[vqf?$"](UU 6OY `k]ۍg2b?Sm,Yyc\yx2bt-xj "I O"\'L:4gT7d2DR 8Wn*<+#$ c;40 WNiqEpƧ #@M#d2cm巩^Jm~0}:Q`@Y鵛J6ņ@t!B`S.Lk]@NM):Bެk5taP0)&;2\)KM Of{; != =w:|I0p@U/8Ǜ.tu/kÊ4XW`C; PQn7Ixҙ(Becg|8(T+(O!ah +T$ aᓧ(}sJA{F1$W,HO(6'$ɉ+<<[UN kO.|\!7E0fjIdl邾ߤT yu~b[$φJ8.f xؗ6~Etc†͟4pJof¿ 6u! W# WDZJ(ci %C^ )0#\tse!*MFoh=2ftl?A94c(s+jKeq.SSM}(LW0oWCmt#]l(p!a =6E8]xq_Ϋ9`r,D8t9^݂OWdi1]8X]]iE?.| F<Ӆ8wqb .C /V`x<,co\Wj;e!=50 lL-vE?gw8DB<@0vhݛAwH~ƻʣu$?8J8G ` Qh+=Ϟh[Opգk1gNu=$9A PIZTp@` GUOSppӚ<`ZyVRl8]Z%aŭ oh}2Gpq2.+C;Ѕ" - LD"]0*@ Mn1 B<–ڒ."¥bΐ SfS@x/! 4:w: \`p@-0U}W{WZL-U)j[}NhZ2G4Jhpc Ou ^.EiL7"3gppe]O觚| !a$BRabaPkXt"s](}BaFm邰~cRѼ`Nvս>!vн'BDnU}5/} UUCG~[f##` ITG 0DRs;4mnGM(e4B#dѼ5[o?x Q֫OhE=,Yr$YQ񝡡+ bQ8;`:' Q] $nPk 48B1lrܢj7?楗2Gx Ƈ% "8]wT .0x `+3tC( .Mz$]0 &|ޗSR 5}e@4L¿ -@p )?b(WtDC]`x18Qg4B<LHbFgW1B)# Dˉ.V'ۥ#. Jҩ'QRr|sX5`f/O]\AvIw4ĆKL=ő|rz6VP91^KEH#E](4BR0zsm^]0#Ba%Mn]ďnUľ0f#\F5v.0X` (u7p ]/1 TH\`x3ּJ'MgI\,#` QE">P#+O.8Ͱ2"L6\pp,e c$ .W@)i1W-hw-pc\Qү`orti! taxAICu#\~~8•4<dK9ŀI` d $IpBΫ,*Tի]DHrF{{ŀ"pgox&!3 _Ѡ4-\-l obLWlL=Mvm? "6s.#; d c4?:\|Ζ.{% JV" ;5-0GNG`~21`GD:5/Ȁ> C^01Vm4!QQ^|weE*eD|2%l8BJMİkzc$1D%-x']<Hwt?ƥ"i5G>;Me .5x W}C*(n}襅~P)iE}d{0d]5NQ8]U.]n}6p! tzaG.ܼyII8]D_;Sk,!+q/XuCf~4bj&)j <%2 !T&>\UuYt2]ݢklZrodl0JZ{( Nfqx E;aLW.o~ ޏ\R.4\'V5:\ƅQp7u0]yNK.h] _u,#]Xӗ64z91BG" ! 3E#,0{8G(}EUJwqh<]bdޗ-ʔ._=o[8](yUlwtP\u|e{.aQp %l75\@Z7풤!]G." VT-;AB^u ߿`Ѕ垬w pQɠ e!P@r`4W+(S=6סNCx-]Q2<إiW)$c&ÔM8~xf BM"?];SKzaR'Ұգw( ʂ?Cc」ﭪ iFY$lDk:6QhrԌrJ3hgmxwkcϮwq$ (" HUu?nW|: ѣ]ߡUPR7v…MkE_KtM_CxhX3 H<@C`YV _縄GS I4VP I ZYAP8be0djS& _-[XBmC_TXY_tt\YAlp.0]hY F >_=]8}G ez̜@ٶX- j[KJG9Z/ӴO KlCQG8+}s!RRGpT+J5B|`/PFu l)7$~JI`Ieo\$.fEdkqO݉ 1U0B< ;6Y86^򺪾L^ rgL!if9JqAi[rTps%U 9HI]eToٲ=kD'L[ q>Օ ? ƀbQ0j 7.4ta?<ߥ.rvjN[4$`5Bja*YI+̈́Gxl_?&Uۙv~Cu?&b k=$:#\ dXZII^`$.c>Jf^O$+<ҵzRj$>'?ܶE"NI|ŤzwPσ+SH`kq^fBpq"f3M K2EDUv eJЊxmJ3| bֳ  \ yFS;̟ u$6 :2)L E%/Ua]YD`nIŧ2efBzMU{ȧŸE_bJ\yðB1\Y)ޠ(F(8O*dFI@+Z$9v鎗@2V `x"Tl"ҏA$6aL Hp!5j/fMl) 'NtY#B'4<1qrx/Jx!? @(WTkÀBl=Etz+Kb((L,@ J|!]/o~&T.~eRҧHcr }=xi6Jҝ3yA2qwi1i&x_NOs>q]+_ܘ >hM[ g$ǻkf:dg&cX p8i4N +t __BߙAMRg(`umI < )ÿ3ax8@A s>sa$ [wmIfshuBCd$rh*L 92$xX ef*bKZo$5BQնs>Fse-׼pX2<+t?T1U" QsC_ӂ} .a-%9J/9^/ 4D6iYEb" -.#M0 Yh;F vO_p?{vY *JD^ux׉T!cwZ8huSAB*Y d;&H@T1.QB{u \`qb_2{-;> 7EԼȉ >0I:Z  `<U|~B\ 5utm4Ę4.[}]-SoT~_KyDC5vR~b{MEsw#A *QΡ2 hS~;1I2rarEh1.ܬ>LJ&qA!ť}|T>lBZBh~{l(`yۑ_yVkg ~+@, pѶAe!^;D>wv(Sޜ"Ԏ (9'L:`4Fy=:@\'^0@u6\8iariͧk[p-F(I*ͺYSz<^y`(S* %ރ*bH[C$2Y^RǑqq%UP?M^PJh"icb^ 3Д0pUMn۰v2_x<.8G#j ̙ HxGKUDž{<72+r%Lh8\ąԩ  #:ӔW9xTr(< 'T (6 %VW$_̟o-4J-5!R[?|\|qlh;+PDW k!o؄" r`JlEp3\0d@ B\eW%G8qe虺a\t q&\0  >6qFKڶ5>&.N֗^:WjֵgT$l *Q6PpmxxRmn5*B dDTS,0WKJLh|9khFܾu҈PxCCsSdf6Dh6lGjM\pe$SzMYR(|nP#,ą:W:#T13Ƹ)-%F5\)|a1ZwK<4кv~|2pe>Ҍ6F~ `0Q`|UQN Og` & Y(|B|*Cϋk#JKƵ5" s0н5E(Bp=98 a_hlqY 6V`p^SzN/  @&Ć uzȥ>Tl(G~8AqАAl k.' WTs F ![-R'-4+a-*֜B%%ɮɶ'D` %{ #R#Y!f8}#JKZ.L^l8~K\2'RgxBgkȔِQ#<|L6x\`ڦ_SD yiG8qz Ht{ogx;:}G3F i: &.0)(Ctf <@|ZnkJ<@/W71,`E~{BrHb<Ri I H2ؔ`݆Y% ߯ickKKG n_礊-V\<ܳlqz k~XX/\z1t IcbRnL^U{-7"&+$)0ǥ#?W*ˆKCE6nD0z@u6.ׯrA Lk]VU; ק\BŖаy^4w- sSoe,,'tW !5#|wkȁ׶=O9wgu4򼫵*ǓjQQ]e`V=~ <-^iǯ]*!$kyǯ--}s,v́I?>Z{|bVQl[FHcCEX(מNfYnЄ}pB#e >zLM!LH .eU3F|kM9kP!z4D@l@ӡ-9'uce(r&;N2lXtLVqdeڲ)؄)+Jb5{k%2QH]9'gg/48SZKȖtT"`D YoI;\`zk[7L&a3CBd#2 _ĒW6 :QsY.$mϲy\ЁWNܱ>p&yoGK}h>]ej `6ligP|341'S7^XQfV7)׼xMB`0N ;\/hK+(^! Sc$阮\3'!lG^WI_fg-3kKK(,NalpW*2S|b8Yfi E4YBX -[Qf+s 6#L\`0qz(hO`i-|ol &(@x[ 7g!i0M)}Ǝj:CSg 40JqB [&N$Ic36 *-6 0kvqVB0* Ǡ''Vn}$R沼72#b&4@><^ %@RVteQS9CZIH/JkX>Ca,YB2XO#$յe6,zIUnٚtR)Vuh8U?{$1\D%4nz0$=pu1tmpC6 \L඙Q5Tp0! 4QY{`}uIi7*`.fC)G õ#0P{P1)3{{߻ DT힦 grNӓ.7wncla> p"IpC…-d@5Mdޥ9q^D Ka`s~1"Pbq]1@'D;VȎlz9tM]zK.YQxPx5pa%0:E`x"+ٺgSz"-6C4yB@H?)H3q& C:Eu@3x^i-`9 $tW4t|<ą,Y7շ$g)ƿ<3 %Sz { `pg{K=b bV"yhZ]Q3*wxҗ6{o6|$V&KW(T7& Ĉt[Hus%``n8Qݦ$Ӛt\׎ڇ3"?|Á&w,{+W f tZ%ˇr'{h_Zɮ$pO_4 d[.9J3GM #8Pg*0PjWg a3h]4D"$ +NȎLv4@)V$ }#޷ 8R݌) gf"gUdL1 l X/Ȩp0\xQU8y. $Lj0F\ D.p!xD(\j[$IIR/t={\pI]w_,\8,g 6Դc$ ]*kx_'[jmʈNQܠJK4+s1dM^> /6ͿLiUD91 L%b B\^z{f0;㇌ rZUSlp!F4 Fic&4L\WìWߏ܈e8\yL80 zV8@yC5a(0tYRV.3oX HYU`p CYU{3%UUsZ Z FJe;if 4M\*WCarDzI`^6 MRo_tm6Ñx|e!@akZ5qv:}o.\(]uXAd@/hѱ'Ԯ [Fh3d ؀ w>7ZI3 axSeւ3ui02$aB:q!Db! 3}+3>5o@$ Lq F׷ua*lMfH⨦"ą َ0qUy"\Ly :5~ÉsM"T$E%2qU-J̱|x5gߺc7{cLI$P}Xے6`ѵ䃧-^wY. rHS>Gk!{e>i f>cs偋4i@+<ڳy65H{ 1EZ`jIɅHqLMkf LA\ q!(K_Tp4>ݤ9.(e'WT3ącMy4{fHޛ$TP`G䳢uf05=^S!RG#k%Й|b}ީkl]R0ԌM+ 8ek`so(!k2ƅXǪ*Y~Ѡ_8S IISؾvg4 y,mp C.EQBfkO0~3q!84-*JDp8.UN>Jc /Lsy%E[GhaO ~_-C` GgFetl}7c.{b0 jշ@'p#`cJI^Y(? 4@͐+b;ss=Sv8 O|8x .جOϦ+U$. loSYH4G3s0TaGxJh I lb!༦9)N֧vw{2.4Y/߲H" xO,A6@iw8H*Y4)}y Lk_8m۲;F|4P B|YaMVZ,0q1~XrGyY 5b92ƅLے'2Dp"1|cN51y/pLsfH℮Ѿeu,hSrDR^Դ4.xs?HWw\ם3D ůYZ ww8:W3lOfҘ[O $2 oY/o&~TMV `0>gf-Dx]R*w?hoBu6ۚ2wَd Ǽ 0J$LȆ\Ǐu$/V8iT@}+(XuIb/rJՒ X)+ &,疲 W1e-84e!pl?.DlDbbtt%0" .Y3|M"7[<^̆cNڢMk2-MLAy OL:L8,DB~q;#ۖqэk9^/dE߿mnwb?= \Y;מ\vl fcՀPCқjwmw o]x`džhpc\F?awwB ׮ؽYt)ąS\P5喉ӫˏ#lГ.vṊ "3hmYR4D;81?a"H^8Gһ,}ieD  zl?Pm@l`cL'"Eھ`VH9 |$k=̇np6Unc/{#5uO6UX^]َDL\F\B(nkJ,vdz1 [ZSCCS=OkKAMPlI / aGڗ_ɲ5; ͋y P$qۖcGmZD$^{քci[~W,'$N)c(PP*: 6m_fcˠ~H|"`3d0X~]WгMRX"ZY%C5mMsƻ5p **$Z? cBf;KHE zkJU˪9U=G3t 3 RtVPQԤZ~ũ 6 \q/Mku鵵i*\֔aUJ/&GEػZV1PY޻1BFIҡՖ鸻y | Dw9d q/#FB+9 NUt*ah%/$w8sٺ쑭jZ֣)h9 Z '+TgceP4/ j sKD?0!C[r:^Wjx\xW Ҵ񲌺tFEBJ5$YSgXx=_”:Ii6hRV&{0(S*v9}ŷFYVr z<ݾ_.픀P&UkFo]ϖ aN5{!@n wbqf3vگkz<} sgK3x\ a%ѣ$$N &+gbO g!m~8drHTyZG8ȏjAJ]RolMJtTnr}b6}c/MLɭL,m$ x9_y?PqgwpS|'*e)e'K ~^AGǴN{VA$1!dBÉ/$Չ[^ l!\lMZˢiVhCxy{zȾ2J|߄7-,D;.cuyWes ,)mx.:a{R| 1gb/\82&V)J@$ACR@\xaJmMJGuxQ}3l(ML" |?_\.%?XX ȲR3׍[?6V>Oy|޾εfl⽙}{/-߲onnw/&= [xEIdحMLkY$N>q~:Ke`y^/g8dav”]GVkZ?(6\ &U R ._I&_SB 7嚖=OOe>x 5GE1psg `[v4ԬT[w@I&78;k=*Y0Xad? >#D`Q0h0ķԶ'w|65RtkX<0,SvmTD&.xB@O( )'+0k~TˬPb}ϰŸ< SoekZlF~͊WTmJcf"E0g-q[CUzC1BXUǭK%Eggm₝$ʚi0!L}y>坞ܖh*K/EE)K+tgpq% D |zpksCn@gIu*;{# |Ț!–YN~gE\sč|2U`:z_om G|aiN_5¹XΥ8~! x:|A C&<͐D1x3;Iڴ.3aK?9q.P/Śʞ|HL]++gkZJ(csVTrSn@^0}`ʄ%It}˿5%|=,Ӌk$M8ka$6ަGXF8wu!/_Ӭ΄(CO].#r:Q.!S#y`Tй?~-> m^geu3L\Y!/e4*I IDATLVL?֑e~{O1Z oI7_J IִJRQUTs9/g q6ieԟ'x ,nޟ$lօWß$<62!M M?49splx dx5 }܄-")eb3x s{2Jȳzm>U\L\(VX Xo0Xpx[֠O ]kI<4^0PYJ1tL{[ X).,&p`K!"$QL Tk\Ws>x͒eJӛ,1eptt> Lza< t"84kh$6QHS\PD1 ^nd,vBOB^S6\(V5 @q&EV[ה`4.Mo0Lkp$ 9S){*v(<7Ja(!|KV, S$8|0%*@o(l}U!d|*2 HG0]č[\3dO$"hp=/4{غL2QmO=4g 3%kb.GQ.&.eJ'~?8'=r?8V Ur@M3X `1<ѤکeTxnPfw|A+ֱlA;<%Dr°!/]A)_`<8DoGHaJ_p 'f#>4^lk[%n8&Lל8ᾃ" [ "P XԲ'"hp=X4aD窡o y doqGc$y`IKJ^|h1}c$!{%7۞4}{gܒm'˃%iϕ*@<%dl};Å湹9o00u$&ԊOb0 xG˓ 3kێo\)tUT0籿,4''Noyju*H\!@F0/'ힽvcLi5 *M˺.Q@biCGMhIlq$ q `$ ڀe0!4ݘğ.GZ[y H͊?> ce적K (SXΎ ikP#ir@j{Dmׂs73؍&%Rd@pWLPJ(N4^M&S (Ich֕bH?UgӲ,`pR_M&GI9=z-J'a\D' 4c+H RkM@DSf-\!䔮unRͳpsL@Hg~k7I3aÅFBRv"֔/ BeO롰PRB$Iqjvgm;Jb*%VpRjGђLq''ۗh W(&MC zI~ez?/1x}s]τ Ը(-L[wy EuACeՔq9Ӌj-,u4'c q|"xE\zfKhblJNP0(_T@;sY8} 0LNj{LW@TC\Xr5udEIr6 :|p @H| TU"?ĐbE!@U{(/sZ8C}+vRBIZTR@\pf0d # \8T3AyBMI.iM9@q &)N"#IqFSv͟1xL$mHk Z"^|p6@eP \qm(2<[T?j_;5X=aؼ l$xb gIi tm݋&x,2erb[hx1P` ']!7׀D݌3PZ (7Z8VH %%LVx-GUo϶8YRhVZؗHj_֗ ,k\@H\xfRKKM!{\$)X,$ '5 ^%1 GUܴ-:~^`8WnJ$I0wW5V`0r@밦,mp0C x!Bz`prc[ |97k}FCfV7.A IJo[vg֍ R/.1tm94zE͹98(D.f*<7OP`@}䋪z#sq!HvoIޙ%.x\1V9 >k.@U՟ KX#/106TG 3s~(IJҍ^\f `r"_ZuX!=#a;ҿ16<=lz`p,W}fm`]4 }vn^(yS X f)]FXeF1gTCU- X6Lk{;ĵ3g@l:>yGc13ne7^!)]gЫ{\ޭn^Y{EnM(\x.Ҵ,q 1'2wF7/f^Mm;C0UǗtH~dTqƃUձr5%oPLq٤;pǽLz81Dž^FB,b31Ǵ(PDJB,&|@aһmD Wߚ~L}s??3\8TmȟW+#:" @0yNqo޻,0,8m-0$e"ݽ]E7Sӛ>e xR I:HҴ;30 w񈖧v|J= pnA! /E Q c]|fD_ w׌GS,6q,q00Ѕ78 Q!"`9D$P`3 qJԕ]` 22f>B ?"s}m_gw/y03o]OduU.WEܤ`Z[2?0Y|#B `:Sl-b02%;Ĉ>e?+Rɏ }yE*A4_W4`f7]2ۆ51 a 4Xt1l$VrPUF|oJ1d*Yu۴ fLPpN۷ ԞѶec_'F)LZ +CkgKitѝSFmn_)Оq ++~T C $Ik9Oie{#٣ .̬MBj)d I0+}\G4U7"#DΣ25/`=&F@1me xGyh -}׵y}b)VPb_(Zp c/Pu\]Ah̬;+ч(ɸuIqUhFt)T]@!@l 4uѝn ySdy,tzw⠐MVl11V))HDŚʨ{4e F\RڤGM:` 0QPpօ{۔W Ɓ#]M &z|c4}F%K*2d X63;5G;LmI)VL'(׉f$vÇ7؜.3cJd4l (lYý{-g{TJ?u%A ж,RJh[5ҫ1`}ZY"({q(p>(Ԭߵ}xjႉn6xMӜ*7?{{;q2&I 5Q](S&l2ϓaJOZY2$@.BHȴ邫T,q!ZJ^&NNy91txKxef0ã)%z!P༮%,EIRLd `t|k%|`,tL!Hu4V`ׂmUyѾm{4}vtӋ!BpHңr'*]8F 'm/:,gpeSd .BZ2\p9η/`4wٙT8޴E} * "PY*tӨчFx٬~]06PD ~ZsHD3W;{lPڍٚbBq&/UrYKtGI/3fr(nc0Is!l!h "T㢮// {yݳ `$48m^!V;_0-=C/') Qh+S],GO/udm6{ϡ`c&?]0zEnUq.v]#K&)%>{ ) Ò=&\޾nD74I =(ూ2kNuC2y.\^Wk/H$d3Mer.n'li-8Y?ߤ9`僚XS[&'((\|obL{4J ׹@KHb2-)ʙ;q#d#WտkZGu}Nlր%ko,õ{@#H?:ج~|ߘ؝Je59y2빂#30j-\rLUN#++.wb_h̐l{BX۴ . HvvLq sAp!TgoE9sM-gBj)*AU`mo}M9"c0Ba' :lɏ%vڲڵ m a t=/EP&=N>.g G3칐`1|A<(:m_}^dXpnz/ m]`v%#@~]){ jY fEx"eu탍O\Rcg϶((0e[={4eRRA})Y BP9 J6`Y|\+JKOΝ΁xcc{t)azW~E(isxn@;!HDӋjs!>]㱠O8S 6w`e 5+o:\(Q`\[+ue]'$έLʙbB>uXAI BxE"{\vą$"Ie(4Qh̻>{)J\fBM tjobh`3P,9%? F9H17WedN]\}|5y%D{nAC!XySvesNe {ogEu?nw44%KD163Lq2&qiTwzC6ETDVdq&18dI4!FDU޺u~sO:6rvww=S.(}4[U*Bmg8KmȉNOnV!>|=# ޑ1N DDP<^˅ຊ:;."~:ȷִ u :wwQ*XyIM# '$+=r" RGP!!k[]!FEC :dz=A1%? }-AmV D9֓ E~HfU)vOUlSf.9dYD>8Zt֚\ 0z݄pE(FvFͺ, ,˚go_,Á[tꦇ$Ogo:0DVAM_;  /.t,X ֺ`A}5LZȺ5SnH]T PZʴT \/tb%RNH4t a2Bvܿuqw~AؒAUgwF  Q)BO<Œ~PL͆taԅ&L66)|df3(rO.G j.~DIep~ |]5l8!q IDAT+Ac䭝pPd.,`p) >aE֭. UEM(RfRh0Bߜ"ydzFƃ?[.u,Ώ6ue0h@V o?k<0W C7D/ Pp .1ҙ#KHz(ѡ!=յ9a޴Sg[ ESji(Q a>fG;Hd;)aݜ%qS?ɺ>5Wz4eBRFN2Y,|s?5}(HN>DA(K'1ڑ#햽Ku~zЁ'`1-w[5`ƹF Ox J#n` 4q.tQ![!`tpڲ~2sMٜdQƩ}ّG,:{ڋXi,fYai_*.֙4>?MlyL/Y\(d-eDb5`Ps7KkiNJ.y\F4 +ÀkjX5Z£'?)kw_C}.ωB'AC;/f("_Zp! +m& keq]e ŲFӅP BZRHx#r\İT呆 +lGNVB`G%[c k6΅ )=3Ƥ jR:rh~P0~ @ñ/xq0NѴus7%g0035]-s6L孥,\(zzD#XPMvu?Ҥ)G4mߒ'bɏ,y3BOënrA}]]ZSBga .n^ %7HW =ȝ` E {l轒rxRjRDbM.0Vॄ1}pAdk5-_ QMtt|z4qZ-%S)4`G<2`gcӠ:-|j( YW/ ΄SŃͨ,:z';;&NBK t}BDpO>*:4Tq|d IV\5 "U-P)g#k8cP-9vf.W(qUPI~J_(eY-k'%;)yLm&ވw6bl]S`\ oQE൚Oӣ ()\.ZJ]1GS JD)bX\Yy|Yai={7M۱nk&VpPLЀȔJ(;䓷+p0DKwSxKYrzUKf n\){Q)S(Ft\HܥWY6<>QҥRV[2Q촬 e5%dT ({)}hgJL2mY4\Մt=^\4cj) RhUyd /n~OS1႒dkc\ؙ0w) `Z9Q:L%؀y%QM # 4}sݕ!: 0APyYYw^kw\E^3DL|F[ }!:sOrCMh9n '͸#OYb^eD >3:V( ', ,;̈Īv&@̸kPHi6``Y9L`y+\5RLbk̠l"?{rpgœI^ W Ii4}zL Q6k:2JePܓؓRWU} 컴 ^VPV`r#\pR#5MߘxW{^ s$N##>4v{,ki~vUҽwqæ/Ro/ciVy qJY֫fe J)[ O'2߷付8j'BRZtǿ FJ?ٯ_A %H IߺniP;szr s|ʊ _bP\QQvs L{hċ v9όu ӵA2Đ]V`yU؟y*a@TQc*}DFsހ°oEF>n=oӇ9 `nh7D/E w"Wi NoZ̆lܪ$lNJPux9|q:(H~531ypag2s|EfCaZ#s tb b SZo^ƚ=%f9L9a$jOIA3 \A9!\HWZgTsCcyq? SeV(qױ5 (pI BMQ,Q4~Lw+)9L6 (iݪ|)s|+&]ww~L( XɠAlp'OIl! ޫ@r!Z<"[p22ĸ 9^|Z`aBVC( ?\ؙLh &,Ͱjl%eQ CI<2i++#nJلdYRsOįN8qB0vk{ -/um|F,ٍMbIaqn0Rt~2L) i>ҽ&յX%1i(Y{pA}uޯpNhZ) ? 2ַW>29N1DM3 Ui2S`hg~b|@Tu?uiքǯhN}SWxx]pMK@>2l)>rr8!m|xz=؈ Bۗu iMZH|*i2בi ôMVj^x܀x?˳lYr@䔝`b``YR7ckӞJ+)ۗ~-:o{_>(ce` dcԠ@9.솶N}vYn֞aV Ӎ y C o=?@hCY]%ZGp\2hCpAӴi8GuG)%QD uC'B7Nٕ0+s10p6e`&=?=m΀o$- ?yPp'Y M; 8%s"O4Mbj3 ާyD ZTO~@n1yV**|,G5OiFL$Nj|vTivQ?b7?&´9mF4MN>?EqNAyaPB('!j'^3A…= { =8 5BtVFa^**Xsf'xdN4D;K$@!|96(nYcmD'Ik"IZRG+k'0P88h̗on㦡=2D#JeyӢ iR:@Vf˚ nל>,}J< CD5mŒ8Us#JXHB4XX#v$o's2D O\yp-HT:(4E+\YL!E,.BË8ρV/#=up<9)hHf8w-S4mx,:Kx ]?qЬ$}A|s.C`ʽIe?΁7N` LGgu/!g7Dd#fZm]}>?Zf(> F HyԲ&>.mxBX^kaae11!4-\xf\ݿ B %j-x;i`b`3s4mû5r3(9b-##qC@R$g pC9?++/gߦsk|ʛ )|+/ u=1{ؼAXJ1:4ƒ,W 3>10P#,!+ .TRf%>kL82Di<7a>~R#'G'ǫo}o 7ٿF+\nhk=Wס#_~F(TY!fh  JkeSY'a Y iL7z;MO^ˁK0̉!]ܿӯ/@_B&1jaK&‚7lx!̕A4 "%H jSW}`fy;ik;;wc<6qhڔ3 {''ݷ/cx%Ӝ50e$=eCד;u7,uS/Kct-;@\=SH0Ư_++c#Ͳ)AHd$xlb^RdN-Vb//DJ`,R QPBLj+l$\B<+[~?0{Fc.pqZXK LYֿHpJi2\3k!@9{M gj!6@Sަ (V(|b#W{my7eSBU%H;螤U0\7C ~ #( N)2pqǯ<~{,f\7tttT HqW7#Ɠ"/6~sֽy5OS[(#1t_f' Ga1g(+FiS$h-H5éX`Gqֹu=q2&[qA-wdv. O IDAT1F]2RFvb0"C^{+1kAdnJ3We ($+( &uQ"Q<ñӗ>qA?{Vf+YViF}AGTDzN>pę!l:ˎ_F<ǟ#t0]7XO{;|붶x&$EB*N'oE8f.D~%u9Qs!cN{]"QݰMfth IuR+jq$?WEܓtÃv _1 Go v`Iւ )ЗhS.}5Muϻ%X0)JYTHe_BTKbۅ_JRakWHDn@,7FjAW7lbFdlPqo1"4}א%4E2 mZy|`YRғ=6cj֑B9asӱˉKpRpK`(x–N29;s1)D7[ =9i:c~!~=kH}:q# pa !u/4lLBAЖVn68.p1/}4;*`%ln f/7';ʎtoK$.1'l)7\m,K,t @@Rd7h4@ʅ-~5;۴tfҌ޵dhGG޹s(Ð& xfԐr2۹U6儭kT.Iw|lSP]rOoP}nϹ_d,GGISÛw:v•{{BCς^ւ+ߍbw  L>ClY0)*sJ2 u޵|+/vCBR P Y~T<٥{3k% P)BWrS 4?^H]?FipAX& {]?] otDl҄-o# x;m~9p҃e%vmV5uC^rYauJxb"n-0V8F7v&op6e%X!*b)%R0!i(rJI!JM @0òBnCjT5PMӘx}v) +Z>+;Gkɓ&T(USjܽ8d[2ӗ?f!?x҃ cQ˼o,#SS{ۢ\>רT繿 "{V.Xv ϏQVsXM˨MX ~I:'4| 3 Doeؠf0F">0 xD)xT $Xxr71UO[~ in&94`fû48gj$qC48)Z5@v0h.0!r<͐vOR +\5-crփo&>!cs׃9%> 8MU y!%4,{gh 1kR%(şNRąz;pXD &EN_&ܖPDExDɶwT*V7Xnl{2y9bTT<%AíO| WE ! _)5>/$c&4s*-uͲ4D  PDR2v~ ^V`PE-S ,f-trȲ8%x!-(RB.y-8dY0Rյ< n8%U("Bd]n*@j%N( p+{GČ~_,+e<.BÌoxtݳ%(fᆐt5wab:lLF{I}4Cg2ݴ +[4 o6ΆE.Tj'TB qNV佛Ͼ{99O<{GÏrDHX֛IkmC%C=ُ%ؙJt:Aw}5u^0N~~vO6~IE.:uDE'dei a8-Sx8EF6B\6~@:ݜ ;lÚ,ea)O! Vs<;8yh=NS1sOe}h-(YMJ/[_:oWOUHYZ>c.LL%@ i,QJcy \|fOUUln쭤eLl@ : pkՀ̖L' o{3~DPqْp֑LkcR]/p.䰄2&.rSJ7x)\@I`iKϞPQ~/^0 [{# f6\B,pƙnJU6,!;4<ϪRD\;cq-ӥЫ5MF+H4pUlv/.f-f<Fx y P!4q=awË5}9vQ%v¾wm)!;2iT?O\MO+?9';;~7i'[fnz!uFWE]S;pįfl8wPBXN:{Ŗ4@)9EG$<#IЊӹ9sזsO'UƲqhM`if~IaE!qaǤF4_}+{eH}k &.q!Y2I_(ڏ@n@ ~6# s}`loĻI덄y[& Ҋ T l]y kLAnj +Roc]fGbo, Xgs̼鱅3\HWPe}ņqD`N ""l"\yUW߼u-WzqڸhY ,R}2q}RiAi﨔+*1Kz"J$|T)tp*V0}14Mxph`a ,HlXH>qh# YjiH;!jl_-CbV:J`̛mÙ mqB+p#0Atȃԅ LPTR %SzrSrCєs |t~e;o;LmzԵ\}K,t5d֪$==?!W,W'Nkhkb^Beu{T*BH gc5-$/.tS(n$KzrSo̓5HaĤ_nm<8RS8V`iF:`g6,Yf Re68J W~9|,1zeby~ =ZPڸO{b'sؿ# 0mnp&$P|C-5a l[{d6эye6 H PqQ.pG,AQ7\f(Xb7WX@]^e͍yN MS?(^i0UR^WҸm唒RejQ _ 6|"ʖMxp*=/1z:S/$ES@V Mkp'%ȫN~NNf͐ #iGaCXqNۦ|#$ DV`ڙHR= rE @tERpr#oXo*o ## ~\[C5Xk6ls/fCԋL[5HР}%cGOhHfp+TZ o=g~ի^If-0_ N( )^,ޢ6.L$v&~Z7ppi99L61, ڊRisOn@@Li# Ol ̆绺HXfx 'UáyϷC`Z^odD9D^UHG]zիvJB)޵lVx1G"#]P`1ы -nYs}v>T7'M_9LYi0T\g1Hq 8Q w7N:c&9n,]i}Kf3E-' T]۪A.G&];41r7:բ ؘA`Mz\jZ`[֌*żY@@@ L".xۢnd fPT$G0}0o2OE}'~apK٠HiPBr$i@gbK.%4wշŭ̉Bi* eɝ=Qt/Bu/%鷻+=T1}13>p{'*vsJGv}'s 7nԎIc8M!(ޯi:EӼ&JQP]8{hzyqECHlHo֫Wcr 4x)v̵-9hP8xz%i.JDxR fgg3K=!ҫ^[ޢY B)HS;v'-;ɝdr|}HWR̠*COw?1{TtߦR6~bTAs<1į3y~ pl>KIi ~9 ~i"#˾oس Oh> ivt^-_ wwЬk*W Ρe } v,-lTݲNq_oCWL6!Dr"Rcj[w_ +Z|8q2#B܆65y@l:~vC@Ms>tXµ}5YPoN3x<.Hi mP]u-k/qe@Q,o -7BImP8G/_T߲3@n2 g1ݞ!?c], je2rԘi8h p8Y6vVYd:^5JֵJpe ; bi@kH|PV_@r~,洆AT5NysՃ$W2c.ٷpM 'Xe _F4"4}rARhj`rXFweA ia5t>4HRhQ@C_nTy{Ol"T5 >e&-Nah {:" 3JQ`)!dȟ%p憃 L&ᤶon"Q?% _uwx7p>(~l>i`B!(8B%B;!,DV P0VmmT9}%H4_3(! 8X!,Q1 EXrIד^BU 4 ,A>^N8Aa͑`P}W=4;X)0t@A fWk*-u6> rFiMZ܉On&ӭrL*̈-f Md"op!"<ӿx谬m{ʈx ~N󶚃+Y[S,*b,k[<Yd=4"«I n]x⏦ <7_b ± D~⒳^۵⒳ IH1p`@Aibk( /reWrDF6iCL-f8|v˚\;*/:KgR?ơ{uC{.Dwܧ sh1[V0U24Mx2D1Tj xhrȈP\%h'pd+4B  ) C0VHP!mf '.$G9yufG˹wh_!z]+Fwi!K4hBCXCubME9H7exn'u~W,/+Zܷ" !Bpثz{%IP Bah0NZM&3D]t&cl2n"zffk"N"GTjgV .:b.;~\]OFT8 G?Vw]sY۲k d@c׫-e Lfu+vOSV L }L6C(o$T[1?h=0tDnAs95~2d ^a:qXSr`,:~΅D+ pG^|c+*W@HD@ ":ngoݿf*>PI6+b.VEIV@`BqX!͔(B)$9)ҙΗ]t&m_|֊Knz8fgeʤO'"AV ;@gP[]X -򝇾&ٸg4v>CJAOiqJ9(g\m?s:/ \IjP1A!nʃg-EX˄T1$u+,(Qbn3INjSں~'n14U()A 47DK y˯/PQNzZ" fԱe !) !lw<&)؜᭜_;fи++v⩣!̔a SIHa!9 uvvQڰl'SgL]PJF7MK'Nu5K 9euISg) 2fK$W/n)4Er\kh]ʾ%2mKE1( :T=y- !ݝ |=Y<=.QDE%H2 8q+yѠR#µ֥48B*8mOU_aѨ{Uߡlh8K!ֳǏo)0$wL؏vv6d=eG<ʆ.9Ώ<},^vVQ4q4~u5ԎAX[j}\1WI׷ٗL}w(UO<YT (1V C8!QOLrT*c`fC8iN%u.Fڭ}W#EiKµƚgjZ!J"xr$ A  ,W<&VDڅm BhPzꮺS\1@׻)O;LϺ2d$:Oy{UҳSE^^$+T E մsA[wq5MiQ"+:e!-IM(-X$":g\}܏(G2W"_fgCBC@d?w!씅I-W`^Q1B(0]Ц&sQ B/xdasvQ%&NsE7(E2Hﰑ+v7%d]:13J{?e *3sòs@-ցe[_aS?Uw}j _ߺLɉM$ǡVUهXZ+ 4 fY҅8Z5 &o: 1YXy7>;*&ߤfk|$@1bp0IZ{=dJ+"+j5&8jBֲhGoe(A`t~ .PZNo4Cs\H6q)ѳX"df~zu) tsRpwгtӱ{X>X}VT*DCk 1JR*RBH7|cK!y$ႸL +\u؟}NE\w}VC[Fi~\(IwVOqgַ*Slk!p>՛xu1b[UH`*dg6d6SCLt|N kՐxb@Ï*UljYCÐ?=zТ |8[ _ofx=ֻY}E !I/и/ezW1C\"bEUյ첨wd)1!Ύl]ĝ$4/+pwNB0m.W䷥r:uZCہ}ϬoU6{΀r(1eRVD$hlpz6D2@@7|"54]B~e⩗:OT>K1 #rœuV酿&_Xxo 5$SߗgO`G+&3\1U/\SYSw4%$HY2DRn"$Ú^]^.(|RB)q=lJ3AtxX={gR#Å*Mt4]fl}j(ҍD8EJ"qH"B=,. Ū7 qs]Sly|gg yh46_[1v Y63XG~8{UPr+{v^Y|IJ8٘ J\p=DXA) U]4Aຖ,U;'6i$ǓIAϋ4Ipk >SZ\Xڽ_qA8r:SIZK|x|t1oa?SϿd\tc['::_N /VCr/ײ /PEi>HAXc*O~3^Qan=^0;"]gj qw۫s5QH:i4E)pDN? ~[%\n^,땄yvzcaq}qآ]Da;:ܸ`0B#8rZxw;ih@fCL̎&LPj0?".O0I `rʖ-P">fe3oe3͐ LG=hzhO1\^<~lx3?Ҵ"[Bn.ݓpa`]kO$G=$I MoweAs 3 ռ00ļ}O8g|$AN=~]Gf>mPFr;|.L V2]XH4PP 3H4!jAʲ ᥠ!XL؄"!&20znR J$0QpӫVZ.3 XSF vjϨ$;.)T 8+K-iɋ "+{2P Gr)0:Q}T~S:f2 pp!̠3\OOYp/ȠuBlASWt-Hfxzڍb '6.0P{%zC kCTw`d\KAvf.ZІh-0䝔 `HpI'q$BTHyn?xS g-Y{ 2tʀ.9:Czᔏǐܕ6e6CBm6@?), >VE.;)'hn邆mܐZf"g<ɦLzWȏ`OV_bᣮ5Z|pK o3d`+fl&r=,Nѫ^ J8j6TA:${fCAub%4iQ&e3d, LdQꥇ^1X4,PxhV0hOb 9rf370y'Rd>&^W JX ,!P> stream xT1R1 @Xl^@EA 7C(.P}l@2 `RڬW9o1.p*x@$ J`Ta*x);$ByIq!Qk7p+602M蒜,3zO7wjW>[^{ q_·g@'?_znYl)nYB*¡R.9+G$G6!$eּۑMc1)kvɦ9zMg ,<ڮڻv9&oQ۳>J. ioDRwka鱷͝dK$|afگe> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 8 0 obj <> endobj 9 0 obj <>stream 2014-05-07T10:30:19+02:00 2014-05-07T10:30:19+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 10 0000000000 65535 f 0000000661 00000 n 0000002235 00000 n 0000000602 00000 n 0000000465 00000 n 0000000015 00000 n 0000000446 00000 n 0000000725 00000 n 0000000786 00000 n 0000000815 00000 n trailer << /Size 10 /Root 1 0 R /Info 2 0 R /ID [<2B299BCE385BE148F1846BF08D29E48A><2B299BCE385BE148F1846BF08D29E48A>] >> startxref 2358 %%EOF dune-functions-2.5.1/doc/protocol_achen_2014.txt000066400000000000000000000052461313314422100214340ustar00rootroot00000000000000Function Space Bases - for now only depending on GridView (maybe also for Grids or other entity sets - tbd) - Global interface minimalistic (only provide enough information for computing container sizes) - main interface through a LocalView obtained from the global basis - Prototype implementation for PQ1 and flat global index in dune-functions LocalView - LocalView returned by value (can have multiple views at the same time) - View can be bound to and unbound from elements and provides access to a bound element - Concrete interaction with a bound view through a nested tree object (name tbd) LocalView Tree - Tree represents an element-local tensor product space - Leafs correspond to a local finite elements from dune-localfunctions - Tree is implemented using dune-typetree - Leafs can map leaf-local consecutive indices for shape functions to - a unique index with respect to the entire local basis tree, which is consecutive and 0-based - a globally unique (for the entire function space) multi-index. The exact semantics and properties of this multi-index are not defined yet. There may be multiple classes of multi-indices with different properties and complexities. A very simple index would be of length 1 and consecutive. In general, indices can be of varying length and can contain non-consecutive entries (e.g. for the GeometryTypeIndex). At a later stage, those classes will need to be precisely defined to create an interface to container backends that will depend on the exact semantics of those classes. - There are interfaces to obtain either a single global index or to efficiently populate a container with all global indices for the currently bound grid element Smaller Changes - GridViewFunction was revised to work with new GridViewFunctionSpaceBasis - Replace FunctionHandle for derived functions with shared_ptr - Functions now longer inherit from enable_shared_from_this - Convenience interfaces by Carsten to convert to / from callables (via std::function) Open Questions - Container backends - Index transformations (for systems / blocking / etc.) - Avoid interface restrictions w.r.t. features like automatic backend construction (PDELab) or additional information like local sparsity structures (Carsten) - Semantics and properties of canonical multi-index classes - Constraints - higher-order derivatives of shape functions for non-affine geometry mappings - dune-localfunctions: Several smaller issues - revise global valued interface of dune-localfunctions Homework Oli: port additional bases (P^k) from dune-fufem Christian: functions interface for PDELab Christian / Steffen: discuss minimum backend interface from PDELab point of view dune-functions-2.5.1/dune-functions.pc.in000066400000000000000000000005061313314422100203450ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ CXX=@CXX@ CC=@CC@ DEPENDENCIES=@REQUIRES@ Name: @PACKAGE_NAME@ Version: @VERSION@ Description: dune-functions module URL: http://dune-project.org/ Requires: dune-localfunctions dune-grid dune-typetree Libs: -L${libdir} Cflags: -I${includedir} dune-functions-2.5.1/dune.module000066400000000000000000000004671313314422100166230ustar00rootroot00000000000000# Dune module information file Module: dune-functions Version: 2.5.1 Maintainer: dune-devel@lists.dune-project.org Depends: dune-localfunctions (>= 2.5.0) dune-grid (>= 2.5.0) dune-typetree (>= 2.5.0) # We suggest dune-istl, because it is used by the example programs. Suggests: dune-istl Whitespace-Hook: Yes dune-functions-2.5.1/dune/000077500000000000000000000000001313314422100154055ustar00rootroot00000000000000dune-functions-2.5.1/dune/CMakeLists.txt000066400000000000000000000000341313314422100201420ustar00rootroot00000000000000add_subdirectory(functions) dune-functions-2.5.1/dune/functions/000077500000000000000000000000001313314422100174155ustar00rootroot00000000000000dune-functions-2.5.1/dune/functions/CMakeLists.txt000066400000000000000000000002241313314422100221530ustar00rootroot00000000000000#install headers add_subdirectory(analyticfunctions) add_subdirectory(common) add_subdirectory(functionspacebases) add_subdirectory(gridfunctions) dune-functions-2.5.1/dune/functions/analyticfunctions/000077500000000000000000000000001313314422100231525ustar00rootroot00000000000000dune-functions-2.5.1/dune/functions/analyticfunctions/CMakeLists.txt000066400000000000000000000002621313314422100257120ustar00rootroot00000000000000#add_subdirectory("test") install(FILES polynomial.hh trigonometricfunction.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/functions/analyticfunctions) dune-functions-2.5.1/dune/functions/analyticfunctions/polynomial.hh000066400000000000000000000050531313314422100256610ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_ANALYTICFUNCTIONS_POLYNOMIAL_HH #define DUNE_FUNCTIONS_ANALYTICFUNCTIONS_POLYNOMIAL_HH namespace Dune { namespace Functions { /** * \brief A scalar polynomial implementation * * \ingroup FunctionImplementations * * \tparam K Scalar type. The polynomial will map K to K * * This class exists mainly to demonstrate how to implement * the \ref Concept::DifferentiableFunction concept. */ template class Polynomial { public: //! Default constructor Polynomial() = default; //! Copy constructor Polynomial(const Polynomial& other) = default; //! Move constructor Polynomial(Polynomial&& other) = default; /** * \brief Create from list of coefficients * * Coefficients are ordered in accordance with * the corresponding monomial order */ Polynomial(std::initializer_list coefficients) : coefficients_(coefficients) {} /** * \brief Create from list of coefficients * * Coefficients are ordered in accordance with * the corresponding monomial order. This will * move the coefficients from givven vector. */ Polynomial(std::vector&& coefficients) : coefficients_(std::move(coefficients)) {} /** * \brief Create from list of coefficients * * Coefficients are ordered in accordance with * the corresponding monomial order. This will * copy coefficients from given vector. */ Polynomial(const std::vector& coefficients) : coefficients_(coefficients) {} //! Evaluate polynomial K operator() (const K& x) const { auto y = K(0); for (size_t i=0; i dpCoefficients(p.coefficients().size()-1); for (size_t i=1; i& coefficients() const { return coefficients_; } private: std::vector coefficients_; }; }} // namespace Dune::Functions #endif // DUNE_FUNCTIONS_ANALYTICFUNCTIONS_POLYNOMIAL_HH dune-functions-2.5.1/dune/functions/analyticfunctions/trigonometricfunction.hh000066400000000000000000000024431313314422100301310ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_ANALYTICFUNCTIONS_TRIGONOMETRICFUNCTION_HH #define DUNE_FUNCTIONS_ANALYTICFUNCTIONS_TRIGONOMETRICFUNCTION_HH namespace Dune { namespace Functions { /** * \brief A linear combination of trigonomic functions * * \ingroup FunctionImplementations * * \tparam K Scalar type. The polynomial will map K to K * \tparam sinFactor Factor in front of sin * \tparam cosFactor Factor in front of cos * * This class exists mainly to demonstrate how to implement * the \ref Concept::DifferentiableFunction concept. */ template class TrigonometricFunction { public: //! Evaluate function K operator () (const K& x) const { return sinFactor * std::sin(x) + cosFactor * std::cos(x); } }; //! Obtain derivative of TrigonometricFunction function \ingroup FunctionImplementations template TrigonometricFunction derivative(const TrigonometricFunction& f) { return TrigonometricFunction(); } }} // namespace Dune::Functions #endif // DUNE_FUNCTIONS_ANALYTICFUNCTIONS_TRIGONOMETRICFUNCTION_HH dune-functions-2.5.1/dune/functions/common/000077500000000000000000000000001313314422100207055ustar00rootroot00000000000000dune-functions-2.5.1/dune/functions/common/CMakeLists.txt000066400000000000000000000012451313314422100234470ustar00rootroot00000000000000add_subdirectory("test") install(FILES callable.hh defaultderivativetraits.hh differentiablefunction.hh differentiablefunction_imp.hh differentiablefunctionfromcallables.hh functionfromcallable.hh functionconcepts.hh indexaccess.hh interfaces.hh localfunction.hh localfunction_imp.hh optional.hh polymorphicsmallobject.hh reserveddeque.hh signature.hh staticforloop.hh treedata.hh tuplevector.hh type_traits.hh typeerasure.hh utility.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/functions/common) dune-functions-2.5.1/dune/functions/common/callable.hh000066400000000000000000000070051313314422100227670ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_CALLABLE_HH #define DUNE_FUNCTIONS_COMMON_CALLABLE_HH #include #include #include #include namespace Dune { namespace Functions { /** * \brief Wrap a Dune::VirtualFunction into a callable object * * \ingroup FunctionImplementations * * \tparam F Some function deriving from Dune::VirtualFunction * * This class provides an operator() that forwards to the evaluate * method. In order to allow this F::RangeType must be default constructible. * This class is copyable and ownership policy of the wrapped function * (see constructors) will be the same for all copies. * * This models the \ref Concept::DifferentiableFunction concept. * * Using this wrapper you can e.g. pass a Dune::VirtualFunction to * the standard wrapper std::function. */ template class CallableFunctionWrapper { typedef typename F::Range Range; typedef typename F::Domain Domain; public: /** * \brief Instanciate from reference to f * * The CallableFunctionWrapper will not take ownership * of the provided function. */ CallableFunctionWrapper(const F& f) { f_ = Dune::stackobject_to_shared_ptr(f); } /** * \brief Instanciate from shared_ptr to f * * The CallableFunctionWrapper will share ownership * with the provided function. */ CallableFunctionWrapper(const std::shared_ptr& f) : f_(f) {} /** * \brief Forward operator() to F::evaluate() * * This uses the default constructor of F::RangeType */ Range operator()(const Domain& x) const { Range y; f_->evaluate(x, y); return y; } private: std::shared_ptr f_; }; /** * \brief Create a callable object from some Dune::VirtualFunction * * \ingroup FunctionImplementations * * \tparam F Function type derived from Dune::VirtualFunction * \param f The function to be wrapper * * The returned object will only be valid as long f is valid. * You can e.g. do the following: * \code * // Create some F derived from VirtualFunction * F f; * * // store callable directly * auto fc = callable(f); * * // store callable through default wrapper * std::function stdF = callable(f) * \endcode */ template CallableFunctionWrapper callable(const F& f) { return CallableFunctionWrapper(f); } /** * \brief Create a callable object from shared_ptr * * \ingroup FunctionImplementations * * \tparam F Function type derived from Dune::VirtualFunction * \param fp shared_ptr to the function to be wrapper * * The returned object will share ownership of fp * using a shared_ptr. You can e.g. do the following: * \code * // Create some F derived from VirtualFunction * auto f = make_shared(); * * // store callable directly * auto f1 = callable(f); * * // store callable through default wrapper * std::function f2 = callable(f) * * // Create some F derived from VirtualFunction and only store * // it in the callable wrapper * auto f3 = callable(make_shared()); * \endcode */ template CallableFunctionWrapper callable(const std::shared_ptr& fp) { return CallableFunctionWrapper(fp); } } // namespace Functions } // namespace Dune #endif //DUNE_FUNCTIONS_COMMON_CALLABLE_HH dune-functions-2.5.1/dune/functions/common/defaultderivativetraits.hh000066400000000000000000000045441313314422100261730ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_DEFAULT_DERIVATIVE_TRAITS_HH #define DUNE_FUNCTIONS_COMMON_DEFAULT_DERIVATIVE_TRAITS_HH #include #include #include #include namespace Dune { namespace Functions { /** * \brief Dummy range class to be used if no proper type is available * * \ingroup FunctionUtility */ class InvalidRange {}; /** * \brief Default implementation for derivative traits * * \ingroup FunctionUtility * * This class provides sensible defaults for the range * of derivatives of functions with some common \p Domain * and \p Range types. */ template struct DefaultDerivativeTraits { //! Range of derivative for function with given signature typedef InvalidRange Range; }; /** * \brief Default implementation for derivative traits * * \ingroup FunctionUtility * * Specialization for Signature = double(double) */ template<> struct DefaultDerivativeTraits< double(double) > { //! \copydoc DefaultDerivativeTraits::Range typedef double Range; }; /** * \brief Default implementation for derivative traits * * \ingroup FunctionUtility * * \tparam K Scalar range type * * Specialization for Signature = K(FieldVector) */ template struct DefaultDerivativeTraits)> { //! \copydoc DefaultDerivativeTraits::Range typedef FieldVector Range; }; /** * \brief Default implementation for derivative traits * * \ingroup FunctionUtility * * \tparam K Scalar range type * * Specialization for Signature = FieldVector(FieldVector) */ template struct DefaultDerivativeTraits(FieldVector)> { //! \copydoc DefaultDerivativeTraits::Range typedef FieldMatrix Range; }; /** * \brief Default implementation for derivative traits * * \ingroup FunctionUtility * * \tparam K Scalar range type * * Specialization for Signature = FieldMatrix(FieldVector) */ template struct DefaultDerivativeTraits(FieldVector)> { //! \copydoc DefaultDerivativeTraits::Range typedef FieldMatrix Range; }; }} // namespace Dune::Functions #endif // DUNE_FUNCTIONS_COMMON_DEFAULT_DERIVATIVE_TRAITS_HH dune-functions-2.5.1/dune/functions/common/differentiablefunction.hh000066400000000000000000000105751313314422100257470ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_DIFFERENTIABLE_FUNCTION_HH #define DUNE_FUNCTIONS_COMMON_DIFFERENTIABLE_FUNCTION_HH #include #include #include #include #include #include #include #include namespace Dune { namespace Functions { /* * Default implementation is empty * The actual implementation is only given if Signature is an type * describing a function signature as Range(Domain). */ template class DerivativeTraits=DefaultDerivativeTraits, size_t bufferSize=56> class DifferentiableFunction {}; namespace Imp { /// Traits class providing type information for DifferentiableFunction template class DerivativeTraits, size_t bufferSize> struct DifferentiableFunctionTraits { /// Signature type using Signature = S; /// Range type using Range = typename SignatureTraits::Range; /// Domain type using Domain = typename SignatureTraits::Domain; /// Signature of the derivative using DerivativeSignature = typename SignatureTraits::template DerivativeSignature; /// Interface type of the derivative using DerivativeInterface = DifferentiableFunction; /// Internal concept type for type erasure using Concept = DifferentiableFunctionWrapperInterface; /// Internal model template for type erasure template using Model = DifferentiableFunctionWrapperImplementation; }; } /** * \brief Class storing differentiable functions using type erasure * * \ingroup FunctionInterface * * \tparam Range Range type * \tparam Domain Domain type * \tparam DerivativeTraits Traits class to determine range of derivative (defaults to DefaultDerivativeTraits) * \tparam bufferSize Size of stack buffer for small object optimization (defaults to 56) * * This models the \ref Concept::DifferentiableFunction concept. * Small object optimization is used to store the given function. * If its size exceed \p bufferSize, memory will be allocated dynamically. */ template class DerivativeTraits, size_t bufferSize> class DifferentiableFunction< Range(Domain), DerivativeTraits, bufferSize> : public TypeErasureBase< typename Imp::DifferentiableFunctionTraits::Concept, Imp::DifferentiableFunctionTraits::template Model> { using Traits = Imp::DifferentiableFunctionTraits; using Base = TypeErasureBase; using DerivativeInterface = typename Traits::DerivativeInterface; public: /** * \brief Construct from function * * \tparam F Function type * * \param f Function of type F * * Calling derivative(DifferentiableFunction) will result in an exception * if the passed function does provide a free derivative() function * found via ADL. */ template = 0 > DifferentiableFunction(F&& f) : Base(std::forward(f)) { static_assert(Dune::Functions::Concept::isFunction(), "Trying to construct a DifferentiableFunction from type that does not model the Function concept"); } //! Default constructor DifferentiableFunction() = default; /** * \brief Evaluation of wrapped function */ Range operator() (const Domain& x) const { return this->asInterface().operator()(x); } /** * \brief Get derivative of wrapped function * * \ingroup FunctionInterface * * This is a free function that will be found by ADL. */ friend DerivativeInterface derivative(const DifferentiableFunction& t) { return t.asInterface().derivative(); } }; }} // namespace Dune::Functions #endif // DUNE_FUNCTIONS_COMMON_DIFFERENTIABLE_FUNCTION_HH dune-functions-2.5.1/dune/functions/common/differentiablefunction_imp.hh000066400000000000000000000044211313314422100266050ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_DIFFERENTIABLE_FUNCTION_IMP_HH #define DUNE_FUNCTIONS_COMMON_DIFFERENTIABLE_FUNCTION_IMP_HH #include #include #include namespace Dune { namespace Functions { namespace Imp { /** * A concept describing types that have a derivative() method found by ADL */ struct HasFreeDerivative { template auto require(F&& f) -> decltype( derivative(f) ); }; template() , int>::type = 0> auto derivativeIfImplemented(const F& f) -> decltype(derivative(f)) { return derivative(f); } template()) , int>::type = 0> Dummy derivativeIfImplemented(const F& f) { DUNE_THROW(Dune::NotImplemented, "Derivative not implemented"); } template class DifferentiableFunctionWrapperInterface {}; // Interface of type erasure wrapper // // Notice that the basic interface of polymorphic classes (destructor, clone, ...) // will be added by the type erasure foundation classes. template class DifferentiableFunctionWrapperInterface { public: virtual Range operator() (const Domain& x) const = 0; virtual DerivativeInterface derivative() const = 0; }; template class DifferentiableFunctionWrapperImplementation {}; // Implementation of type erasure wrapper template class DifferentiableFunctionWrapperImplementation< Range(Domain), DerivativeInterface, B> : public B { public: using B::B; using Wrapped = typename B::Wrapped; virtual Range operator() (const Domain& x) const { return this->get()(x); } virtual DerivativeInterface derivative() const { return derivativeIfImplemented(this->get()); } }; }}} // namespace Dune::Functions::Imp #endif // DUNE_FUNCTIONS_COMMON_DIFFERENTIABLE_FUNCTION_IMP_HH dune-functions-2.5.1/dune/functions/common/differentiablefunctionfromcallables.hh000066400000000000000000000123551313314422100304740ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_DIFFEREENTIONABEFUNCTIONFROMCALLABLES_HH #define DUNE_FUNCTIONS_COMMON_DIFFEREENTIONABEFUNCTIONFROMCALLABLES_HH #include #include #include #include #include namespace Dune { namespace Functions { template class DerivativeTraits, class... Callables> class DifferentiableFunctionFromCallables; /** * \brief Wrap a list of callable objects as derivative sequence modelling \ref Concept::DifferentiableFunction * * \ingroup FunctionImplementations * * \tparam Range Range type of function * \tparam Domain Domain type of function * * You can use this to implement a differentiable function including * a variable number of derivatives using callable objects. * * This models the \ref Concept::DifferentiableFunction concept. * * Note that using makeDifferentiableFunction will be less verbose than * creating this wrapper manually. */ template class DerivativeTraits, class F> class DifferentiableFunctionFromCallables { public: //! Signature of function using Signature = Range(Domain); using RawSignature = typename SignatureTraits::RawSignature; //! Signature of derivative using DerivativeSignature = typename DerivativeTraits::Range(Domain); //! Type of derivative using Derivative = DifferentiableFunction; //! Constructor copying the given function template = 0> DifferentiableFunctionFromCallables(FF&& f) : f_(std::forward(f)) {} //! Evaluate function Range operator() (const Domain& x) const { return f_(x); } /** * \brief Get derivative of DifferentiableFunctionFromCallables * * \ingroup FunctionImplementations */ friend Derivative derivative(const DifferentiableFunctionFromCallables& t) { DUNE_THROW(Dune::NotImplemented, "Derivative not implemented"); } private: F f_; }; /** * \brief Wrap a list of callable objects as derivative sequence modelling \ref Concept::DifferentiableFunction * * \ingroup FunctionImplementations * * \tparam Range Range type of function * \tparam Domain Domain type of function * * You can use this to implement a differentiable function including * a variable number of derivatives using callable objects. * * This models the \ref Concept::DifferentiableFunction concept. * * Note that using makeDifferentiableFunction will be less verbose than * creating this wrapper manually. */ template class DerivativeTraits, class F, class DF, class... Derivatives> class DifferentiableFunctionFromCallables { public: using Signature = Range(Domain); using RawSignature = typename SignatureTraits::RawSignature; using DerivativeSignature = typename DerivativeTraits::Range(Domain); using Derivative = DifferentiableFunctionFromCallables; /** * \brief Constructor copying the given functions * * The arguments are used as implementation of the functions itself * and its derivatives with increasing order */ template DifferentiableFunctionFromCallables(FF&& f, DFF&& df, DDFF&&... ddf) : f_(std::forward(f)), df_(std::forward(df), std::forward(ddf)...) {} //! Evaluate function Range operator() (const Domain& x) const { return f_(x); } /** * \brief Get derivative of DifferentiableFunctionFromCallables * * \ingroup FunctionImplementations */ friend Derivative derivative(const DifferentiableFunctionFromCallables& t) { return t.df_; } private: F f_; Derivative df_; }; /** * \brief Create a DifferentiableFunction from callables * * \ingroup FunctionImplementations * * This will return a wrapper modelling the DifferentiableFunction interface * where the evaluation of the function and its derivatives are implemented * by the given callable objects. * * \param signatureTag A dummy parameter to pass the signature and derivative traits * \param f Callable objects implementing the evaluation of the function and its derivatives * * \returns Object modelling DifferentiableFunction interface */ template class DerivativeTraits, class... F> DifferentiableFunctionFromCallables makeDifferentiableFunctionFromCallables(const SignatureTag& signatureTag, F&&... f) { return DifferentiableFunctionFromCallables(f...); } } // namespace Functions } // namespace Dune #endif //DUNE_FUNCTIONS_COMMON_DIFFEREENTIONABEFUNCTIONFROMCALLABLES_HH dune-functions-2.5.1/dune/functions/common/functionconcepts.hh000066400000000000000000000231721313314422100246170ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_FUNCTIONCONCEPT_HH #define DUNE_FUNCTIONS_COMMON_FUNCTIONCONCEPT_HH #include #include #include #include #include namespace Dune { namespace Functions { namespace Concept { using namespace Dune::Concept; // Callable concept ############################################################ /** * \brief Concept objects that can be called with given argument list * * \ingroup FunctionConcepts * * \tparam Args Argument list for function call */ template struct Callable { template auto require(F&& f) -> decltype( f(std::declval()...) ); }; /// Check if F models the Function concept with given signature \ingroup FunctionConcepts template static constexpr bool isCallable() { return models, F>(); } /// Check if f models the Function concept with given signature \ingroup FunctionConcepts template static constexpr bool isCallable(F&& f, TypeList) { return models, F>(); } // Function concept ############################################################ template struct Function; /** * \brief Concept for a function mapping \p Domain to \p Range * * \ingroup FunctionConcepts * * \tparam Domain Domain type * \tparam Range Range type */ template struct Function : Refines > { template auto require(F&& f) -> decltype( // F models Function if the result of F(Domain) is implicitly convertible to Range requireConvertible(f(std::declval())) ); }; /// Check if F models the Function concept with given signature \ingroup FunctionConcepts template static constexpr bool isFunction() { return models, F>(); } /// Check if f models the Function concept with given signature \ingroup FunctionConcepts template class DerivativeTraits> static constexpr bool isFunction(F&& f, SignatureTag) { return models, F>(); } // DifferentiableFunction concept ############################################## template class DerivativeTraits = DefaultDerivativeTraits> struct DifferentiableFunction; /** * \brief Concept for a differentiable function mapping \p Domain to \p Range * * \ingroup FunctionConcepts * * The derivative range is derived from the provided \p DerivativeTraits * * \tparam Domain Domain type * \tparam Range Range type * \tparam DerivativeTraits Traits class for computation of derivative range */ template class DerivativeTraits> struct DifferentiableFunction : Refines > { using DerivativeSignature = typename SignatureTraits::template DerivativeSignature; template auto require(F&& f) -> decltype( derivative(f), requireConcept>(derivative(f)) ); }; /// Check if F models the DifferentiableFunction concept with given signature \ingroup FunctionConcepts template class DerivativeTraits = DefaultDerivativeTraits> static constexpr bool isDifferentiableFunction() { return models, F>(); } /// Check if f models the DifferentiableFunction concept with given signature \ingroup FunctionConcepts template class DerivativeTraits> static constexpr bool isDifferentiableFunction(F&& f, SignatureTag) { return models, F>(); } // LocalFunction concept ############################################## template class DerivativeTraits = DefaultDerivativeTraits> struct LocalFunction; /** * \brief Concept for a local function mapping \p Domain to \p Range * * \ingroup FunctionConcepts * * The derivative range is derived from the provided \p DerivativeTraits * * \tparam Domain Domain type * \tparam Range Range type * \tparam LocalContext The local context this function is defined on * \tparam DerivativeTraits Traits class for computation of derivative range */ template class DerivativeTraits> struct LocalFunction : Refines > { template auto require(F&& f) -> decltype( f.bind(std::declval()), f.unbind(), f.localContext(), requireConvertible(f.localContext()) ); }; /// Check if F models the LocalFunction concept with given signature and local context \ingroup FunctionConcepts template class DerivativeTraits = DefaultDerivativeTraits> static constexpr bool isLocalFunction() { return models, F>(); } // EntitySet concept ############################################## /** * \brief Concept for an entity set for a \ref Concept::GridFunction * * \ingroup FunctionConcepts * * This describes the set of entities on which a grid function * can be localized. * */ struct EntitySet { template auto require(E&& f) -> decltype( requireType(), requireType(), requireType() ); }; /// Check if F models the GridFunction concept with given signature and entity set \ingroup FunctionConcepts template static constexpr bool isEntitySet() { return models(); } // GridFunction concept ############################################## template class DerivativeTraits = DefaultDerivativeTraits> struct GridFunction; /** * \brief Concept for a grid function mapping \p Domain to \p Range * * \ingroup FunctionConcepts * * The derivative range is derived from the provided \p DerivativeTraits. * * \tparam Domain Domain type * \tparam Range Range type * \tparam EntitySet Set of entities on which the function can be localized * \tparam DerivativeTraits Traits class for computation of derivative range */ template class DerivativeTraits> struct GridFunction : Refines > { using LocalSignature = Range(typename EntitySet::LocalCoordinate); using LocalContext = typename EntitySet::Element; template using LocalDerivativeTraits = typename Dune::Functions::LocalDerivativeTraits::template Traits; template auto require(F&& f) -> decltype( localFunction(f), f.entitySet(), requireConcept>(localFunction(f)), requireConcept(), requireConvertible(f.entitySet()), requireConvertible() ); }; /// Check if F models the GridFunction concept with given signature and entity set \ingroup FunctionConcepts template class DerivativeTraits = DefaultDerivativeTraits> static constexpr bool isGridFunction() { return models, F>(); } // GridViewFunction concept ############################################## template class DerivativeTraits = DefaultDerivativeTraits> struct GridViewFunction; /** * \brief Concept for a grid view function mapping \p Domain to \p Range * * \ingroup FunctionConcepts * * This exactly the \ref Concept::GridFunction * concept with a \ref GridViewEntitySet as \p EntitySet. * * \tparam Domain Domain type * \tparam Range Range type * \tparam GridView GridView on which the function can be localized * \tparam DerivativeTraits Traits class for computation of derivative range */ template class DerivativeTraits> struct GridViewFunction : Refines, DerivativeTraits>> { template auto require(F&& f) -> decltype( 0 // We don't need to check any further expressions, because a GridViewFunction is just a GridFunction with a special EntitySet ); }; /// Check if F models the GridViewFunction concept with given signature \ingroup FunctionConcepts template class DerivativeTraits = DefaultDerivativeTraits> static constexpr bool isGridViewFunction() { return models, F>(); } }}} // namespace Dune::Functions::Concept #endif // DUNE_FUNCTIONS_COMMON_FUNCTIONCONCEPT_HH dune-functions-2.5.1/dune/functions/common/functionfromcallable.hh000066400000000000000000000042701313314422100254220ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_FUNCTION_FROM_CALLABLE_HH #define DUNE_FUNCTIONS_COMMON_FUNCTION_FROM_CALLABLE_HH #include #include namespace Dune { namespace Functions { template::RawDomain, typename SignatureTraits::RawRange> > class FunctionFromCallable; /** * \brief Wrap a callable object as Dune::Function or Dune::VirtualFunction * * \ingroup FunctionUtility * * You can use this to implement a DifferentiableFunction including * a variable number of derivatives using callable objects. All * types that can be assigned to std::function are supported, * i.e. functions, functors, lambdas, ... * * \tparam Range Range type * \tparam Domain Domain type * \tparam F Type of wrapped function * \tparam FunctionInterface Interface to implement, this can be either Dune::Function or Dune::VirtualFunction */ template class FunctionFromCallable : public FunctionInterface { public: /** * \brief Create VirtualFunction from callable object * * This will store the given function and pass evaluate() * to its operator(). This constructor moves data * from given function. * * \param f Callable object to use for evaluate() */ FunctionFromCallable(F&& f) : f_(f) {} /** * \brief Create VirtualFunction from callable object * * This will store the given function and pass evaluate() * to its operator(). This constructor copies the given function. * * \param f Callable object to use for evaluate() */ FunctionFromCallable(const F& f) : f_(f) {} /** * \brief Evaluate function * * This call is passed to the function */ void evaluate(const Domain& x, Range&y) const { y = f_(x); } private: F f_; }; } // namespace Functions } // namespace Dune #endif //DUNE_FUNCTIONS_COMMON_FUNCTION_FROM_CALLABLE_HH dune-functions-2.5.1/dune/functions/common/indexaccess.hh000066400000000000000000000121641313314422100235230ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH #define DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH #include #include namespace Dune { namespace Functions { namespace Imp { namespace Concept { template struct HasDynamicIndexAccess { template auto require(C&& c) -> decltype( c[std::declval()] ); }; } // namespace Concept } // namespace Imp /** * \brief Provide operator[] index-access for containers * * \ingroup Utility * * This is the overload for types providing a operator[] * for dynamic std::size_t arguments. * * \param c Container to access * \param i The index to use for accessing the container * \param f A functor to call with the result of operator[] */ template, C>(), int>::type = 0> auto hybridIndexAccess(C&& c, const I& i, F&& f) -> decltype(f(c[i])) { return f(c[i]); } /** * \brief Provide operator[] index-access for containers * * \ingroup Utility * * This is the overload for types providing a operator[] * only for static arguments of type std::integral_constant. * This does a static linear search until a static index * matching the given dynamic index is found. * Since the result type will in general be different * for different indices the method does not return * the result directly but passes it to a given functor. * * \param c Container to access * \param i The index to use for accessing the container * \param f A functor to call with the result of operator[] */ template, C>(), int>::type = 0> decltype(auto) hybridIndexAccess(C&& c, const I& i, F&& f) { using Size = decltype(Hybrid::size(c)); return Hybrid::switchCases(std::make_index_sequence(), i, [&](const auto& ii) -> decltype(auto){ return f(c[ii]); }, [&]() -> decltype(auto){ return f(c[Dune::Indices::_0]); }); } /** * \brief Class representing a shifted multi index * * \tparam Index Type of the base multi index * \tparam offset Number of positions to shift left * * For a given multi index of size n this * represents a multi index with the first * offset entries removed. * * Notice that this does only store a reference to * the passed multi index. */ template class ShiftedMultiIndex { public: ShiftedMultiIndex(const Index& index) : index_(index) {} template decltype(auto) operator[](const P& position) const { return index_[position+offset]; } /** * \brief Return multi index with one more position truncated */ ShiftedMultiIndex pop() const { return {index_}; } auto size() const { return index_.size() - offset; } private: const Index& index_; }; /** * \brief Create a ShiftedMultiIndex * * \tparam offset Number of positions to shift left */ template ShiftedMultiIndex shiftedMultiIndex(const Index& index) { return {index}; } /** * \brief Create a ShiftedMultiIndex with one position truncated * * \tparam offset Number of positions to shift left */ template ShiftedMultiIndex shiftedMultiIndex(const Index& index) { return {index}; } namespace Imp { template struct MultiIndexResolver { MultiIndexResolver(const Index& index) : index_(index) {} template::value, int>::type = 0> Result operator()(C&& c) { auto&& subIndex = shiftedMultiIndex(index_); auto&& subIndexResolver = MultiIndexResolver(subIndex); return (Result)(hybridIndexAccess(c, index_[Dune::Indices::_0], subIndexResolver)); } template::value, int>::type = 0> Result operator()(C&& c) { return (Result)(std::forward(c)); } const Index& index_; }; } // namespace Imp /** * \brief Provide multi-index access by chaining operator[] * * \ingroup Utility * * This provides access to a nested container by given * multi-index. Internally this is resolved by recusive * operator[]-calls with static or dynamic indices. * Because this recursion must be terminated using a * compile-time criterion, the result type must explicitly * be provided. The recursion will terminate once the * result can be converted to this result type. * * \tparam Result Type of result * * \param c Container to access * \param index Multi-index */ template Result hybridMultiIndexAccess(C&& c, const MultiIndex& index) { Imp::MultiIndexResolver multiIndexResolver(index); return multiIndexResolver(c); } } // namespace Dune::Functions } // namespace Dune #endif // DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH dune-functions-2.5.1/dune/functions/common/interfaces.hh000066400000000000000000000036671313314422100233650ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_INTERFACES_HH #define DUNE_FUNCTIONS_COMMON_INTERFACES_HH #include namespace Dune { namespace Functions { /** * \brief Base class with polymorphic type boiler plate code * * \ingroup Utility * * By deriving your polymorphic type from this class you * enforce a default interface for common operations like * clone, clone to buffer, and move. */ template class PolymorphicType { public: /** \brief Destructor */ virtual ~PolymorphicType() {} /** * \brief Clones the object * * clone() needs to be redefined by an implementation class, with the * return type covariantly adapted. This will return a new copy of *this * via a pointer to newly allocated memory. * Remember to delete the resulting pointer. */ virtual Interface* clone() const = 0; /** * \brief Clones the object into buffer * * clone(buffer) needs to be redefined by an implementation class, * with the return type covariantly adapted. This will return a copy * of *this created in the given buffer using placement-new with copy construction. * You must not delete the returned pointer since it points * to the given buffer (however with the proper type instead of void*). */ virtual Interface* clone(void* buffer) const = 0; /** * \brief Move object into buffer * * move(buffer) needs to be redefined by an implementation class, * with the return type covariantly adapted. This will return a copy * of *this created in the given buffer using placement-new with move construction. * You must not delete the returned pointer since it points * to the given buffer (however with the proper type instead of void*). */ virtual Interface* move(void* buffer) = 0; }; }} // namespace Dune::Functions #endif // DUNE_FUNCTIONS_COMMON_EXTENDED_CLONEABLE_HH dune-functions-2.5.1/dune/functions/common/localfunction.hh000066400000000000000000000120731313314422100240710ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_LOCAL_FUNCTION_HH #define DUNE_FUNCTIONS_COMMON_LOCAL_FUNCTION_HH #include #include #include #include #include #include #include namespace Dune { namespace Functions { /* * Default implementation is empty * The actual implementation is only given if Signature is an type * describing a function signature as Range(Domain). */ template class DerivativeTraits=DefaultDerivativeTraits, size_t bufferSize=56> class LocalFunction {}; namespace Imp { /// Traits class providing type information for DifferentiableFunction template class DerivativeTraits, size_t bufferSize> struct LocalFunctionTraits : DifferentiableFunctionTraits { protected: using Base=DifferentiableFunctionTraits; public: /// LocalContext type using LocalContext = L; /// Signature of the derivative using DerivativeSignature = typename Base::DerivativeSignature; /// Interface type of the derivative using DerivativeInterface = LocalFunction; /// Internal concept type for type erasure using Concept = LocalFunctionWrapperInterface; /// Internal model template for type erasure template using Model = LocalFunctionWrapperImplementation; }; } /** * \brief Class storing local functions using type erasure * * \ingroup FunctionInterface * * \tparam Range Range type * \tparam Domain Domain type * \tparam LocalContext Type of local context where this function is defined on * \tparam DerivativeTraits Traits class to determine range of derivative. * \tparam bufferSize Size of stack buffer for small object optimization (defaults to 56) * * * This models the \ref Concept::LocalFunction concept. * Objects of this type are returned as local functions * by the GridFunction wrapper. Notice that the DerivativeTraits type * used here should normally be LocalDerivativeTraits where GDE * is the DerivativeTraits type of the corresponding global function. * Small object optimization is used to store the given function. * If its size exceed \p bufferSize, memory will be allocated dynamically. */ template class DerivativeTraits, size_t bufferSize> class LocalFunction< Range(Domain), LocalContext, DerivativeTraits, bufferSize> : public TypeErasureBase< typename Imp::LocalFunctionTraits::Concept, Imp::LocalFunctionTraits::template Model> { using Traits = Imp::LocalFunctionTraits; using Base = TypeErasureBase; using DerivativeInterface = typename Traits::DerivativeInterface; public: /** * \brief Construct from function * * \tparam F Function type * * \param f Function of type F * * Calling derivative(DifferentiableFunction) will result in an exception * if the passed function does provide a free derivative() function * found via ADL. */ template = 0 > LocalFunction(F&& f) : Base(std::forward(f)) { static_assert(Dune::Functions::Concept::isLocalFunction(), "Trying to construct a LocalFunction from type that does not model the LocalFunction concept"); } LocalFunction() = default; /** * \brief Evaluation of wrapped function */ Range operator() (const Domain& x) const { return this->asInterface().operator()(x); } /** * \brief Get derivative of wrapped function * * \ingroup FunctionInterface * * This is free function will be found by ADL. */ friend DerivativeInterface derivative(const LocalFunction& t) { return t.asInterface().derivative(); } /** * \brief Bind function to a local context * * You must bind a LocalFunction to a local * context before you can evaluate it. */ void bind(const LocalContext& context) { this->asInterface().bind(context); } /** * \brief Unbind from local context */ void unbind() { this->asInterface().unbind(); } /** * \brief Obtain local contex this LocalFunction is bound to */ const LocalContext& localContext() const { return this->asInterface().localContext(); } }; }} // namespace Dune::Functions #endif // DUNE_FUNCTIONS_COMMON_LOCAL_FUNCTION_HH dune-functions-2.5.1/dune/functions/common/localfunction_imp.hh000066400000000000000000000031521313314422100247340ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_LOCALFUNCTION_FUNCTION_IMP_HH #define DUNE_FUNCTIONS_COMMON_LOCALFUNCTION_FUNCTION_IMP_HH #include #include namespace Dune { namespace Functions { namespace Imp { // Interface of type erasure wrapper // // Notice that the basic interface of polymorphic classes (destructor, clone, ...) // will be added by the type erasure foundation classes. template class LocalFunctionWrapperInterface : public DifferentiableFunctionWrapperInterface { public: virtual void bind(const LocalContext&) = 0; virtual void unbind() = 0; virtual const LocalContext& localContext() const = 0; }; // Implementation of type erasure wrapper template class LocalFunctionWrapperImplementation : public DifferentiableFunctionWrapperImplementation { using Base = DifferentiableFunctionWrapperImplementation; public: using Base::Base; virtual void bind(const LocalContext& context) { this->get().bind(context); } virtual void unbind() { this->get().unbind(); } virtual const LocalContext& localContext() const { return this->get().localContext(); } }; }}} // namespace Dune::Functions::Imp #endif // DUNE_FUNCTIONS_COMMON_DIFFERENTIABLE_FUNCTION_IMP_HH dune-functions-2.5.1/dune/functions/common/optional.hh000066400000000000000000000052761313314422100230650ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_OPTIONAL_HH #define DUNE_FUNCTIONS_COMMON_OPTIONAL_HH #include #include namespace Dune { namespace Functions { /** * \brief A wrapper that can either contain an object of T or be empty * * \ingroup Utility * * \tparam T Type of wrapped objects */ template class Optional { public: //! Default constructor Optional() : p_(nullptr) {} //! Construct internal T from given argument template = 0> Optional(TT&& t) : p_(nullptr) { emplace(std::forward(t)); } //! Move constructor Optional(Optional&& other) { if (other) p_ = new (buffer_) T(std::move(other.value())); else p_ = nullptr; } //! Copy constructor Optional(const Optional& other) { if (other) p_ = new (buffer_) T(other.value()); else p_ = nullptr; } //! Destructor ~Optional() { if (operator bool()) p_->~T(); } /** * \brief Assignment * * If internal T exists, this does an assignement * from argument, otherwise a construction. */ template = 0 > Optional& operator=(TT&& t) { if (operator bool()) *p_ = std::forward(t); else p_ = new (buffer_) T(std::forward(t)); return *this; } /** * \brief Copy assignment from optional */ Optional& operator=(const Optional& other) { if (other) *this = other.value(); else if (operator bool()) { p_->~T(); p_ = nullptr; } return *this; } /** * \brief Move assignment from optional */ Optional& operator=(Optional&& other) { if (other) *this = std::move(other.value()); else if (operator bool()) { p_->~T(); p_ = nullptr; } return *this; } //! Check if *this is not emtpy explicit operator bool() const { return p_; } //! Get reference to internal T const T& value() const { return *p_; } //! Get mutable reference to internal T T& value() { return *p_; } //! Construct internal T from given arguments template< class... Args > void emplace(Args&&... args) { if (operator bool()) p_->~T(); p_ = new (buffer_) T(std::forward(args)...); } //! Destruct internal T leaving *this in empty state void release() { if (operator bool()) { p_->~T(); p_ = nullptr; } } private: alignas(T) char buffer_[sizeof(T)]; T* p_; }; } // namespace Functions } // namespace Dune #endif // DUNE_FUNCTIONS_COMMON_OPTIONAL_HH dune-functions-2.5.1/dune/functions/common/polymorphicsmallobject.hh000066400000000000000000000102151313314422100260120ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_POLYMORPHICSMALLOBJECT_HH #define DUNE_FUNCTIONS_COMMON_POLYMORPHICSMALLOBJECT_HH #include namespace Dune { namespace Functions { /** * \brief A wrapper providing small object optimization with polymorphic types * * \ingroup Utility * \ingroup TypeErasure * * \tparam Base Base class type of wrapped objects * \tparam bufferSize Size of small object buffer * * This class encapsulates small object optimization for polymorphic types. * The type of objects passed to the constructor must be derived from the * base class type Base. * * If the size of the derived type fits into the static buffer, then the * wrapped object is stored there, otherwise it is allocated dynamically. * * In order to make the copy constructor work for polymorphic types, * Base must provide clone() and clone(void*). The former should return * a pointer to a dynamically allocated clone, while the latter * should call the appropriate placement-new with the passed pointer. * * Similarly the polymorphic type has to implement move(void*). * This should call placement-new and can std::move all the * data but leave the object in a valid and probably unusable state. */ template class PolymorphicSmallObject { public: //! Default constructor PolymorphicSmallObject() : p_(nullptr) {} /** * \brief Construct from object * * \tparam Derived Type of object to be stored, should be derived from Base * \param derived Object to be stored */ template PolymorphicSmallObject(Derived&& derived) { if (sizeof(Derived)(derived)); else p_ = new Derived(std::forward(derived)); } //! Move constructor from other PolymorphicSmallObject PolymorphicSmallObject(PolymorphicSmallObject&& other) { moveToWrappedObject(std::move(other)); } //! Copy constructor from other PolymorphicSmallObject PolymorphicSmallObject(const PolymorphicSmallObject& other) { copyToWrappedObject(other); } //! Destructor ~PolymorphicSmallObject() { destroyWrappedObject(); } //! Copy assignment from other PolymorphicSmallObject PolymorphicSmallObject& operator=(const PolymorphicSmallObject& other) { destroyWrappedObject(); copyToWrappedObject(other); return *this; } //! Move assignment from other PolymorphicSmallObject PolymorphicSmallObject& operator=(PolymorphicSmallObject&& other) { destroyWrappedObject(); moveToWrappedObject(std::move(other)); return *this; } //! Check if *this is not empty explicit operator bool() const { return p_; } //! Check if object is stored in internal stack buffer bool bufferUsed() const { return ((void*) (p_) == (void*)(&buffer_)); } //! Obtain reference to stored object const Base& get() const { return *p_; } //! Obtain mutable reference to stored object Base& get() { return *p_; } private: void destroyWrappedObject() { if (operator bool()) { if (bufferUsed()) p_->~Base(); else delete p_; } } void moveToWrappedObject(PolymorphicSmallObject&& other) { if (other.bufferUsed()) p_ = other.p_->move(buffer_); else { // We don't need to check for &other_!=this, because you can't // have an rvalue to *this and call it's assignment/constructor // at the same time. (Despite trying to shot yourself in the foot // with std::move explicitly.) // Take ownership of allocated object p_ = other.p_; // Leave pointer in a clear state to avoid double freeing it. other.p_ = 0; } } void copyToWrappedObject(const PolymorphicSmallObject& other) { if (&other!=this) { if (other.bufferUsed()) p_ = other.p_->clone(buffer_); else p_ = other.p_->clone(); } } alignas(Base) char buffer_[bufferSize]; Base* p_; }; } // namespace Functions } // namespace Dune #endif // DUNE_FUNCTIONS_COMMON_POLYMORPHICSMALLOBJECT_HH dune-functions-2.5.1/dune/functions/common/reserveddeque.hh000066400000000000000000000131341313314422100240730ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_RESERVEDDEQUE_HH #define DUNE_FUNCTIONS_COMMON_RESERVEDDEQUE_HH /** \file * \brief An stl-compliant double-ended queue which stores everything on the stack */ #include #include #include #include #include #ifdef CHECK_RESERVEDDEQUE #define CHECKSIZE(X) assert(X) #else #define CHECKSIZE(X) {} #endif namespace Dune { namespace Functions { /** \brief A Vector class with statically reserved memory. \ingroup Utility ReservedDeque is something between Dune::array and std::deque. You have a double ended queue which can be extended and shrunk using methods like push_back and pop_back at the end, or via push_front and pop_front, but reserved memory is predefined. This implies that the vector can not grow bigger than the predefined maximum size. \tparam T The data type ReservedVector stores. \tparam n The maximum number of objects the ReservedVector can store. */ template class ReservedDeque { public: /** @{ Typedefs */ //! The type of object, T, stored in the vector. typedef T value_type; //! Pointer to T. typedef T* pointer; //! Reference to T typedef T& reference; //! Const reference to T typedef const T& const_reference; //! An unsigned integral type. typedef size_t size_type; //! A signed integral type. typedef std::ptrdiff_t difference_type; //! Iterator used to iterate through a vector. typedef Dune::GenericIterator iterator; //! Const iterator used to iterate through a vector. typedef Dune::GenericIterator const_iterator; /** @} */ /** @{ Constructors */ //! Constructor ReservedDeque() : size_(0), first_(0) {} ReservedDeque(std::initializer_list const &l) { assert(l.size() <= n);// Actually, this is not needed any more! size_ = l.size(); std::copy_n(l.begin(), size_, data_); } /** @} */ /** @{ Data access operations */ //! Erases all elements. void clear() { first_ = 0; size_ = 0; } //! Specifies a new size for the vector. void resize(size_t s) { CHECKSIZE(s<=n); size_ = s; } //! Appends an element to the end of a vector, up to the maximum size n, O(1) time. void push_back(const T& t) { CHECKSIZE(size_i); return data_[(first_ + i) % n]; } //! Returns a const reference to the i'th element. const_reference operator[] (size_type i) const { CHECKSIZE(size_>i); return data_[(first_ + i) % n]; } //! Returns reference to first element of vector. reference front() { CHECKSIZE(size_>0); return data_[first_]; } //! Returns const reference to first element of vector. const_reference front() const { CHECKSIZE(size_>0); return data_[first_]; } //! Returns reference to last element of vector. reference back() { CHECKSIZE(size_>0); return data_[(first_ + size_-1) % n]; } //! Returns const reference to last element of vector. const_reference back() const { CHECKSIZE(size_>0); return data_[(first_ + size_-1) % n]; } /** @} */ /** @{ Informative Methods */ //! Returns number of elements in the vector. size_type size () const { return size_; } //! Returns true if vector has no elements. bool empty() const { return size_==0; } //! Returns current capacity (allocated memory) of the vector. static DUNE_CONSTEXPR size_type capacity() { return n; } //! Returns the maximum length of the vector. static DUNE_CONSTEXPR size_type max_size() { return n; } /** @} */ //! Send ReservedVector to an output stream friend std::ostream& operator<< (std::ostream& s, const ReservedDeque& v) { for (size_t i=0; i #include #include #include #include #include namespace Dune { namespace Functions { /** * \brief Helper class to check that F is callable * * \ingroup FunctionUtility */ template struct IsCallable; #ifndef DOXYGEN template struct IsCallable { struct yes { std::size_t dummy[2]; }; struct no { std::size_t dummy[1]; }; template static yes test(const decltype(&C::operator()) *); template static no test(...); enum { value = (sizeof(test(0)) == sizeof(yes)) }; }; template struct IsCallable { enum { value = true }; }; template struct IsCallable { enum { value = true }; }; #endif /** * \brief Helper class to deduce the signature of a callable * * \ingroup FunctionUtility */ template::value > struct SignatureTraits {}; #ifndef DOXYGEN /** \brief deduce the signature of the operator() of a class T */ template struct SignatureTraits : public SignatureTraits {}; /** \brief deduce the signature of an arbitrary const member function of class C */ template struct SignatureTraits : public SignatureTraits {}; /** \brief deduce the signature of an arbitrary member function of class C */ template struct SignatureTraits : public SignatureTraits {}; /** \brief extract domain and range from a free functions pointer */ template struct SignatureTraits : public SignatureTraits {}; /** \brief extract domain and range from a signature (works only for free functions) */ template struct SignatureTraits { using Range = R; using Domain = D; using RawRange = typename std::decay::type; using RawDomain = typename std::decay::type; using RawSignature = RawRange(RawDomain); template class DerivativeTraits=DefaultDerivativeTraits> using DerivativeSignature = typename DerivativeTraits::Range(Domain); }; #endif template class DerivativeTraits=DefaultDerivativeTraits> struct SignatureTag; /** * \brief Tag-class to encapsulate signature information * * \ingroup FunctionUtility * * \tparam Range range type * \tparam Domain domain type * \tparam DerivativeTraits traits template used to determine derivative traits */ template class DerivativeTraitsT> struct SignatureTag { using Signature = Range(Domain); template using DerivativeTraits = DerivativeTraitsT; }; /** * \brief Construct SignatureTag for derivative * * \ingroup FunctionUtility * * \param tag SignatureTag for a function * \returns SignatureTags of the derivative */ template class DerivativeTraits> auto derivativeSignatureTag(SignatureTag tag) { using DerivativeRange = typename DerivativeTraits::Range; return SignatureTag(); } /** * \brief Construct SignatureTags for derivatives * * \ingroup FunctionUtility * * \tparam maxOrder Maximal order of derivatives * \param tag SignatureTag for a function * * \returns Tuple of SignatureTags * * This constructs an std::tuple of SignatureTags for * all derivatives of order 0 up to maxOrder. */ template class DerivativeTraits> auto derivativeSignatureTags(Dune::Functions::SignatureTag tag) { // using namespace Dune::Hybrid; // using namespace Dune::Std; return Hybrid::ifElse(Std::bool_constant(), [&](auto id) { // If maxOrder== 0 we just need the given SignatureTag return std::make_tuple(tag); }, [&](auto id) { // else we first construct the tail tuple with SignatureTags for derivatives // of order 1 to maxOrder auto tailTagsTuple = derivativeSignatureTags(derivativeSignatureTag(tag)); // and prepend this with the given SignatureTag. // This is done by unpacking the tail tuple with apply(). return Std::apply([&](auto&&... tailTags){ return std::make_tuple(tag, tailTags...); }, tailTagsTuple); }); } } // namespace Functions } // namespace Dune #endif // DUNE_FUNCTIONS_COMMON_SIGNATURE_HH dune-functions-2.5.1/dune/functions/common/staticforloop.hh000066400000000000000000000031301313314422100241130ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_STATICFORLOOP_HH #define DUNE_FUNCTIONS_COMMON_STATICFORLOOP_HH #include #include #include namespace Dune { namespace Functions { namespace Imp { template struct StaticFindInRange { template static void apply(F&& f, Args&&... args) { if (f(std::integral_constant(), std::forward(args)...)) return; StaticFindInRange::apply(std::forward(f), std::forward(args)...); } }; template struct StaticFindInRange { template static void apply(F&& f, Args&&...) {} }; } //end namespace Imp /** * \brief Static find loop * * \ingroup Utility * * Run static for-loop from 'begin' to 'end-1' with functor. * The functor is called with \p TypeTree::index_constant * as first argument. All other arguments of this method * are forwarded to the functor. If the functor returns * true the loop is terminated. * * \todo Should this be just the StaticForLoop? */ template void staticFindInRange(F&& f, Args&&... args) { Imp::StaticFindInRange::apply(std::forward(f), std::forward(args)...); } } // namespace Dune::Functions } // namespace Dune #endif //DUNE_FUNCTIONS_COMMON_STATICFORLOOP_HH dune-functions-2.5.1/dune/functions/common/test/000077500000000000000000000000001313314422100216645ustar00rootroot00000000000000dune-functions-2.5.1/dune/functions/common/test/.gitignore000066400000000000000000000001021313314422100236450ustar00rootroot00000000000000*.log *.trs differentiablefunctiontest functionfromcallabletest dune-functions-2.5.1/dune/functions/common/test/CMakeLists.txt000066400000000000000000000001451313314422100244240ustar00rootroot00000000000000# tests that should build and run successfully dune_add_test(SOURCES differentiablefunctiontest.cc) dune-functions-2.5.1/dune/functions/common/test/differentiablefunctiontest.cc000066400000000000000000000226371313314422100276160ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include #include #include #include #include #include //#include //#include "derivativecheck.hh" bool checkTrue(bool value, std::string error) { if (not(value)) std::cout << "TEST FAILURE:" << error << std::endl; return value; } // Check if interface compiles and is implementable by a simple dummy struct DifferentiableFunctionImplementableTest { template static bool checkWithFunction(F&& f) { bool passed = true; using Dune::Functions::Concept::isFunction; using Dune::Functions::Concept::isDifferentiableFunction; using Dune::Functions::SignatureTag; { std::cout << "--------------" << std::endl; // passed = passed and DerivativeCheck::checkAllImplementedTrulyDerived(testFunction, 10); // Test whether I can evaluate the function somewhere std::cout << "Function value at x=5: " << f(5) << std::endl; passed = checkTrue(isDifferentiableFunction(f, SignatureTag()), "Raw function f does not satisfy DifferentiableFunction concept"); std::cout << std::endl << "Check calling derivatives through function object" << std::endl; // Test whether I can evaluate the first derivative auto df = derivative(f); passed = checkTrue(isDifferentiableFunction(df, SignatureTag()), "Raw function df does not satisfy DifferentiableFunction concept"); std::cout << "Derivative at x=5: " << df(5) << std::endl; // Test whether I can evaluate the second derivative through FunctionHandle auto ddf = derivative(df); passed = checkTrue(isDifferentiableFunction(ddf, SignatureTag()), "Raw function ddf does not satisfy DifferentiableFunction concept"); std::cout << "Second derivative at x=5: " << ddf(5) << std::endl; // Test whether I can evaluate the third derivative through FunctionHandle auto dddf = derivative(ddf); passed = checkTrue(isFunction(dddf, SignatureTag()), "Raw function dddf does not satisfy Function concept"); std::cout << "Third derivative at x=5: " << dddf(5) << std::endl; std::cout << std::endl << "Check calling derivatives through DifferentiableFunction object" << std::endl; Dune::Functions::DifferentiableFunction fi = f; passed = checkTrue(isDifferentiableFunction(fi, SignatureTag()), "Wrapped function fi does not satisfy DifferentiableFunction concept"); // Try to reassign wrapper fi = f; // Try assigning a default constructed wrapper Dune::Functions::DifferentiableFunction fii; passed = checkTrue(isDifferentiableFunction(fii, SignatureTag()), "Wrapped function fii does not satisfy DifferentiableFunction concept"); fii = fi; // Try to copy wrapper auto fiii = fii; passed = checkTrue(isDifferentiableFunction(fiii, SignatureTag()), "Wrapped function fiii does not satisfy DifferentiableFunction concept"); std::cout << "Function value at x=5: " << fiii(5) << std::endl; // Test whether I can evaluate the first derivative auto dfiii = derivative(fiii); passed = checkTrue(isDifferentiableFunction(dfiii, SignatureTag()), "Wrapped function dfiii does not satisfy DifferentiableFunction concept"); std::cout << "Derivative at x=5: " << dfiii(5) << std::endl; // Test whether I can evaluate the second derivative through FunctionHandle auto ddfiii = derivative(dfiii); passed = checkTrue(isDifferentiableFunction(ddfiii, SignatureTag()), "Wrapped function ddfiii does not satisfy DifferentiableFunction concept"); std::cout << "Second derivative at x=5: " << ddfiii(5) << std::endl; // Test whether I can evaluate the third derivative through FunctionHandle auto dddfiii = derivative(ddfiii); passed = checkTrue(isFunction(dddfiii, SignatureTag()), "Wrapped function dddfiii does not satisfy Function concept"); std::cout << "Third derivative at x=5: " << dddfiii(5) << std::endl; // Wrap as non-differentiable function auto g = [=] (const double& x) {return f(x);}; passed = checkTrue(isFunction(g, SignatureTag()), "Lambda function g does not satisfy Function concept"); Dune::Functions::DifferentiableFunction gg = [=] (const double& x) {return f(x);}; passed = checkTrue(isFunction(gg, SignatureTag()), "Wrapped function gg does not satisfy DifferentiableFunction concept"); std::cout << "Function value at x=5: " << gg(5) << std::endl; try { auto dg = derivative(gg); passed = false; } catch (Dune::NotImplemented e) { std::cout << "Obtaining derivative from nondifferentiable function failed expectedly" << std::endl; passed = checkTrue(not(isDifferentiableFunction(g, SignatureTag())), "But unwrapped function g does satisfy DifferentiableFunction concept"); } } #if 0 std::cout << std::endl << "Check calling persistent derivatives through shared_ptr" << std::endl; // Test whether I can evaluate the first derivative through shared_ptr persistentDerivative->evaluate(5, df); std::cout << "Derivative at x=5: " << df << std::endl; // Test whether I can evaluate the second derivative through shared_ptr persistentSecondDerivative->evaluate(5, ddf); std::cout << "Second derivative at x=5: " << ddf << std::endl; // Test whether I can evaluate the third derivative through shared_ptr persistentThirdDerivative->evaluate(5, dddf); std::cout << "Third derivative at x=5: " << dddf << std::endl; #endif return passed; } static bool check() { bool passed = true; passed = passed and checkWithFunction(Dune::Functions::Polynomial({1, 2, 3})); passed = passed and checkWithFunction(Dune::Functions::TrigonometricFunction()); auto f = [](double x){ return std::sin(x);}; auto df = [](double x){ return std::cos(x);}; auto ddf = [](double x){ return -std::sin(x);}; auto dddf = [](double x){ return -std::cos(x);}; auto F = makeDifferentiableFunctionFromCallables(Dune::Functions::SignatureTag(), f, df, ddf, dddf); passed = passed and checkWithFunction(F); return passed; } }; #if 0 // Check if recursive DerivativeRange definition terminates // after at most maxRecursionLevel=k derivatives, i.e. if // the type of the k-th and (k+1)-nd derivative is the same. template struct DerivativeRangeTerminationTest { template struct TerminationTest { static int level() { std::cout << "Type of " << recursionLevel << "-th derivative is " << Dune::className() << std::endl; typedef typename Dune::Functions::DerivativeTraits::DerivativeRange DDR; int upperBound = TerminationTest::level(); if (Dune::is_same::value) return recursionLevel; else return upperBound; } }; template struct TerminationTest { static int level() { std::cout << "Type of " << maxRecursionLevel << "-th derivative is " << Dune::className() << std::endl; typedef typename Dune::Functions::DerivativeTraits::DerivativeRange DDR; if (Dune::is_same::value) return maxRecursionLevel; else return maxRecursionLevel+1; } }; static bool check() { std::cout << "Checking recursion for Domain=" << Dune::className() << " and Range=" << Dune::className() << std::endl; int terminationLevel = TerminationTest::level(); if (terminationLevel <= maxRecursionLevel) { std::cout << "Recursion terminated after " << terminationLevel << "-th derivative" << std::endl; return true; } else { std::cout << "Recursion did not terminated after given maxRecursionLevel " << maxRecursionLevel; return false; } } }; #endif int main ( int argc, char **argv ) try { Dune::MPIHelper::instance(argc, argv); bool passed = true; passed = passed and DifferentiableFunctionImplementableTest::check(); #if 0 passed = passed and DerivativeRangeTerminationTest::check(); passed = passed and DerivativeRangeTerminationTest , Dune::FieldVector, 5 >::check(); passed = passed and DerivativeRangeTerminationTest , Dune::FieldVector, 5 >::check(); #endif if (passed) std::cout << "All tests passed" << std::endl; return passed ? 0: 1; } catch( Dune::Exception &e ) { std::cerr << "Dune reported error: " << e << std::endl; return 1; } catch(...) { std::cerr << "Unknown exception thrown!" << std::endl; return 1; } dune-functions-2.5.1/dune/functions/common/treedata.hh000066400000000000000000000151611313314422100230230ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_TREEDATA_HH #define DUNE_FUNCTIONS_COMMON_TREEDATA_HH #include #include #include #include namespace Dune { namespace Functions { /** * \brief Mixin for visitors that should apply the same action on all nodes * * \ingroup Utility * * By deriving from this you only have to implement apply(node,treepath) * in the derived class. This will be used for pre(...) and leaf(...). * * \tparam Derived Type of derived class implementing apply(node,treepath) * \tparam leafOnly Flag to enable leaf only traversal */ template struct UniformNodeVisitor : public TypeTree::TreeVisitor, public TypeTree::DynamicTraversal { // This is only enabled, if we want to incorporate inner nodes. // Checking leafOnly would be sufficient, but for SFINAE the // the enable_if condition must depend on the template parameter. template::type = 0> void pre(Node& node, TreePath treePath) { static_cast(this)->apply(node, treePath); } template::type = 0> void pre(Node& node, TreePath treePath) {} template void leaf(Node& node, TreePath treePath) { static_cast(this)->apply(node, treePath); } }; /** * \brief Container allowing to attach data to each node of a tree * * \ingroup Utility * * This provides operator[](Node) for accessing the data attached to the node. * For storing the data each node is identified via its treeIndex() method * which is supposed to return an index which is unique wrt the tree. These * indices need not to be consecutive but they are used to access an * internal vector. This may lead to wasted memory if the maximal * treeIndex() is much larger then the number of nodes within the tree. * * Before using the container it must be initialized by providing the * tree. The stored data objects will be created on initialization. Hence * the type of these data objects must be default constructible. * * Notice that the data per node can only be interpreted if the * node type is known. Hence the tree will be traversed on initilization, * copy, assignment, and destruction of a TreeData container. * * \tparam T Type of the tree * \tparam ND The data stored for a node of type Node will be of type ND * \tparam LO Set this flag if data should only be attached to leaf nodes. */ template class ND, bool LO> class TreeData { public: //! Type of tree the data is associated with using Tree = T; //! Type used for indices and size information using size_type = typename Tree::size_type; //! Set if data should only be associated to the leafs static const bool leafOnly = LO; //! Template to determine the data type for given node type template using NodeData = ND; protected: using RawContainer = std::vector; // Since we can generate the node data type only if // we know the type of the node, we have to do // initialization, copy, and destruction via a // tree traversal. Once we can use C++14 this can // be written in a much easier and more selfcontained // ways using generic lambda functions. // Until then we need explicite visitor classes for // each operation. struct InitVisitor : public UniformNodeVisitor { InitVisitor(RawContainer& data) : data_(data) {} template void apply(Node& node, TreePath treePath) { auto&& index = node.treeIndex(); if (data_.size() < index+1) data_.resize(index+1, nullptr); data_[index] = new NodeData; } RawContainer& data_; }; struct DestroyVisitor : public UniformNodeVisitor { DestroyVisitor(RawContainer& data) : data_(data) {} template void apply(Node& node, TreePath treePath) { auto&& index = node.treeIndex(); auto p = (NodeData*)(data_[index]); delete p; data_[index] = nullptr; } RawContainer& data_; }; struct CopyVisitor : public UniformNodeVisitor { CopyVisitor(TreeData& thisTD, const TreeData& otherTD) : thisTD_(thisTD), otherTD_(otherTD) {} template void apply(Node& node, TreePath treePath) { thisTD_[node] = otherTD_[node]; } TreeData& thisTD_; const TreeData& otherTD_; }; public: //! Default constructor TreeData() : tree_(nullptr) {} /** * \brief Initialize from tree * * This default creates the data object associated to each node in the tree. * A reference to the tree is stored because it's needed for destruction * of the tree data. */ void init(const Tree& tree) { if (tree_) destroy(); tree_ = &tree; TypeTree::applyToTree(*tree_, InitVisitor(data_)); } //! Copy constructor TreeData(const TreeData& other) : tree_(other.tree_) { TypeTree::applyToTree(*tree_, InitVisitor(data_)); TypeTree::applyToTree(*tree_, CopyVisitor(*this, other)); } //! Copy assignment TreeData& operator=(const TreeData& other) { if (tree_) TypeTree::applyToTree(*tree_, DestroyVisitor(data_)); tree_ = other.tree_; TypeTree::applyToTree(*tree_, CopyVisitor(*this, other)); return *this; } //! Destroy data void destroy() { if (tree_) TypeTree::applyToTree(*tree_, DestroyVisitor(data_)); tree_ = nullptr; } //! Destructor ~TreeData() { if (tree_) TypeTree::applyToTree(*tree_, DestroyVisitor(data_)); } //! Get mutable reference to data associated to given node template NodeData& operator[](const Node& node) { return *(NodeData*)(data_[node.treeIndex()]); } //! Get reference to data associated to given node template const NodeData& operator[](const Node& node) const { return *(NodeData*)(data_[node.treeIndex()]); } protected: const Tree* tree_; RawContainer data_; }; } // namespace Functions } // namespace Dune #endif // DUNE_FUNCTIONS_COMMON_TREEDATA_HH dune-functions-2.5.1/dune/functions/common/tuplevector.hh000066400000000000000000000025711313314422100236070ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_TUPLEVECTOR_HH #define DUNE_FUNCTIONS_COMMON_TUPLEVECTOR_HH #include #include namespace Dune { namespace Functions { /** * \brief A class augmenting std::tuple by element access via operator[] * * \ingroup Utility */ template class TupleVector : public std::tuple { using Base = std::tuple; public: /** \brief Construct from a set of arguments */ template constexpr TupleVector(TT&&... tt) : Base(std::forward(tt)...) {} /** \brief Default constructor */ constexpr TupleVector() {} /** \brief Const access to the tuple elements */ template auto operator[](const Dune::index_constant&) const ->decltype(std::get(*this)) { return std::get(*this); } /** \brief Non-const access to the tuple elements */ template auto operator[](const Dune::index_constant&) ->decltype(std::get(*this)) { return std::get(*this); } /** \brief Number of elements of the tuple */ static constexpr std::size_t size() { return std::tuple_size::value; } }; } // namespace Functions } // namespace Dune #endif dune-functions-2.5.1/dune/functions/common/type_traits.hh000066400000000000000000000046071313314422100236040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_TYPE_TRAITS_HH #define DUNE_FUNCTIONS_COMMON_TYPE_TRAITS_HH #include #include namespace Dune { namespace Functions { /** * \brief Helper to constrain forwarding constructors * * \ingroup Utility * * Helper typedef to remove constructor with forwarding reference from * overload set for type is not constructible from argument list. * This is useful to avoid failng forwarding constructors * for base classes or members. */ template using enableIfConstructible = typename std::enable_if< std::is_constructible::value, int>::type; namespace Imp { // As a last resort try if there's a static constexpr size() template constexpr auto staticSize(const T*, const PriorityTag<0>&) -> decltype(std::integral_constant()) { return {}; } // Try if class has constexpr default constructor and size method template constexpr auto staticSize(const T*, const PriorityTag<1>&) -> decltype(std::integral_constant()) { return {}; } // Try if tuple_size is implemented for class template constexpr auto staticSize(const T*, const PriorityTag<2>&) -> decltype(std::integral_constant::value>()) { return {}; } template constexpr std::false_type hasStaticSize(const T* t, const PriorityTag<0>& p) { return {}; } template constexpr auto hasStaticSize(const T* t, const PriorityTag<1>& p) -> decltype(staticSize(t ,PriorityTag<42>()), std::true_type()) { return {}; } } /** * \brief Check if type is a statically sized container * * \ingroup Utility * * Derives from std::true_type or std::false_type */ template struct HasStaticSize : public decltype(Imp::hasStaticSize((typename std::decay::type*)(nullptr), PriorityTag<42>())) {}; /** * \brief Obtain size of statically sized container * * \ingroup Utility * * Derives from std::integral_constant */ template struct StaticSize : public decltype(Imp::staticSize((typename std::decay::type*)(nullptr), PriorityTag<42>())) {}; }} // namespace Dune::Functions #endif // DUNE_FUNCTIONS_COMMON_TYPE_TRAITS_HH dune-functions-2.5.1/dune/functions/common/typeerasure.hh000066400000000000000000000125321313314422100236010ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_TYPEERASURE_HH #define DUNE_FUNCTIONS_COMMON_TYPEERASURE_HH #include #include #include #include #include namespace Dune { namespace Functions { namespace Imp { /** * \brief The internal wrapper interface for type erasure * * \ingroup TypeErasure * * This class adds some foundation interfaces needed * for proper dynamic polymorphism and type erasure. * * The actual application interface has to be provided * by the user. * * \tparam Interface Class defininig the internal abstract virtual interface */ template class TypeErasureWrapperInterface : public Interface, public PolymorphicType> { public: virtual const std::type_info& target_type() const = 0; }; /** * \brief Base implementation of the internal wrapper interface * * \ingroup TypeErasure * * This class derives from the foundation interfaces * and the user defined interfaces provided by the interface * parameter. It will store any suitable type T to do * the type erasure. * * The implementation of the foundation and user interface * is provided by classed derived of this one. * * \tparam Interface Class defininig the internal abstract virtual interface * \tparam T A type modelleding the desired interface */ template class TypeErasureWrapperBase : public TypeErasureWrapperInterface { public: template = 0> TypeErasureWrapperBase(TT&& t) : wrapped_(std::forward(t)) {} //! Get mutable reference stored object T& get() { return wrapped_; } //! Get reference stored object const T& get() const { return wrapped_; } protected: using Wrapped = T; Wrapped wrapped_; }; /** * \brief Implementation of the internal wrapper interface * * \ingroup TypeErasure * * This class implements the foundation and user interfaces * of the internal type erasure wrapper. * * The foundation interface of TypeErasureWrapperInterface is directly * implemented here whereas the user interface is implemented * by deriving from the user-provides Implementation template. * * The Implementation is a template taking one class template * parameter. It should directly or indirectly derive from this * class and inherit its constructors. * In order to forward the implemented methods to the erased * type it can use the wrapper_ member of this base class being * of this type. * * \tparam Interface Class defininig the internal abstract virtual interface * \tparam Implementation Class defininig implemention the abstract methods of Interface * \tparam T A type modelleding the desired interface */ template class Implementation, class T> class TypeErasureWrapperImplementation : public Implementation > { public: //! Construct wrapper from object template = 0> TypeErasureWrapperImplementation(TT&& t) : Implementation >(std::forward(t)) {} //! Implementation of PolymorphicType::clone() virtual TypeErasureWrapperImplementation* clone() const { return new TypeErasureWrapperImplementation(*this); } //! Implementation of PolymorphicType::clone(void* buffer) virtual TypeErasureWrapperImplementation* clone(void* buffer) const { return new (buffer) TypeErasureWrapperImplementation(*this); } //! Implementation of PolymorphicType::move(void* buffer) virtual TypeErasureWrapperImplementation* move(void* buffer) { return new (buffer) TypeErasureWrapperImplementation(std::move(*this)); } //! Get type of stored object virtual const std::type_info& target_type() const { return typeid(T); } }; } // namespace Dune::Functions::Imp /** * \brief Base class for type-erased interface wrapper * * \ingroup TypeErasure * * This is menat as a base class for the type-erased interface * wrapper that is actually visible to the user. By deriving * from this you get small object optimization for the interlan * polymorphic wrapper. */ template class Implementation, size_t bufferSize = 56> class TypeErasureBase { public: //! Construct wrapper from object template = 0 > TypeErasureBase(T&& t) : wrapped_(Imp::TypeErasureWrapperImplementation::type>(std::forward(t))) {} //! Default constructor TypeErasureBase() = default; //! Get mutable reference to wrapped object Interface& asInterface() { return wrapped_.get(); } //! Get reference to wrapped object const Interface& asInterface() const { return wrapped_.get(); } //! Get type of stored object virtual const std::type_info& target_type() const { return wrapped_.get().target_type(); } protected: PolymorphicSmallObject, bufferSize > wrapped_; }; }} // namespace Dune::Functions #endif // DUNE_FUNCTIONS_COMMON_TYPEERASURE_HH dune-functions-2.5.1/dune/functions/common/utility.hh000066400000000000000000000170121313314422100227320ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_COMMON_UTILITY_HH #define DUNE_FUNCTIONS_COMMON_UTILITY_HH #include #include #include namespace Dune { namespace Functions { template auto forwardAsStaticInteger(std::integer_sequence values, const size_type& i, F&& f, Args&&... args) ->decltype(f(std::integral_constant(), std::forward(args)...)) { return f(std::integral_constant(), std::forward(args)...); } template auto forwardAsStaticInteger(std::integer_sequence values, const size_type i, F&& f, Args&&... args) ->decltype(f(std::integral_constant(), std::forward(args)...)) { if (i==firstValue) return f(std::integral_constant(), std::forward(args)...); return forwardAsStaticInteger(std::integer_sequence(), i, std::forward(f), std::forward(args)...); } /** * \brief Transform dynamic index to static index_constant * * \ingroup Utility * * This will call the given function with index_constant * where i is the dynamically provided index. * * To achieve this the conditon i==ii is checked subsequently * for al static indices ii in the range 0,...,(end-1). In order * to be able to compile this we require for all ii in this range * that f(index_constant()) is well-formed and that the result * type of it can be converted to the result type of f(index_constant<0>()). * If i is not in this range, the returned value is f(index_constant()) * * \param i Dynamic index * \param f Function to call (e.g., a generic lambda) * \param args Additional arguments for f * * \returns f(index_constant(), args...) */ template auto forwardAsStaticIndex(const size_type& i, F&& f, Args&&... args) ->decltype(f(Dune::TypeTree::Indices::_0, std::forward(args)...)) { return forwardAsStaticInteger(std::make_index_sequence{}, i, std::forward(f), std::forward(args)...); } namespace Imp { template class T, class List> struct ExpandTupleHelper {}; template class T, template class ListType, class... Args> struct ExpandTupleHelper> { using Type = T; }; } // end namespace Imp /** * \brief Expand tuple arguments as template arguments * * \ingroup Utility * * This template alias refers to T if * ArgTuple is a std::tuple. * * \tparam T A variadic template * \tparam ArgTuple A tuple of types */ template class T, class ArgTuple> using ExpandTuple = typename Imp::ExpandTupleHelper::Type; namespace Imp { template class T, class... Tuple> struct TransformTupleHelper {}; template class T, class... Args1> struct TransformTupleHelper> { using Type = std::tuple...>; }; template class T, class... Args1, class... Args2> struct TransformTupleHelper, typename std::tuple> { using Type = std::tuple...>; }; } // end namespace Imp /** * \brief Transform tuple types argument using type-functor * * \ingroup Utility * * This is a template alias for a tuple whose i-th type * is given by F where T1i,...,TMi are the * i-th types of the 1,...,M-th tuple of the given tuple * list Tuples. Currently only M=1,2 are supported. * \tparam F A template alias mapping 1,...,sizeof...(ArgTuple) types to a new one * \tparam Tuples A list of tuples */ template class F, class... Tuples> using TransformTuple = typename Imp::TransformTupleHelper::Type; namespace Imp { template auto transformTupleHelper(F&& f, const std::tuple& tuple, std::index_sequence) -> decltype(std::make_tuple(f(std::get(tuple))...)) { return std::make_tuple(f(std::get(tuple))...); } template auto transformTupleHelper(F&& f, const std::tuple& tuple1, const std::tuple& tuple2, std::index_sequence) -> decltype(std::make_tuple(f(std::get(tuple1), std::get(tuple2))...)) { return std::make_tuple(f(std::get(tuple1), std::get(tuple2))...); } } // end namespace Imp /** * \brief Transform tuple value using a functor * * \ingroup Utility * * This will apply the given functor to all values in * given tuple and return the results in a new tuple. * * \param F A functor defined for all tuple entries * \param tuple The tuple to transform */ template auto transformTuple(F&& f, const std::tuple& tuple) -> decltype(Imp::transformTupleHelper(std::forward(f), tuple, std::index_sequence_for{})) { return Imp::transformTupleHelper(std::forward(f), tuple, std::index_sequence_for{}); } /** * \brief Transform tuple value using a binary functor * * \ingroup Utility * * This will apply the given functor to the each corresponding * pair of values in the given tuples and return the results * in a new tuple. * * \param F A functor defined for all tuple entries * \param tuple1 The tuple containing values for the first parameter * \param tuple2 The tuple containing values for the second parameter */ template auto transformTuple(F&& f, const std::tuple& tuple1, const std::tuple& tuple2) -> decltype(Imp::transformTupleHelper(std::forward(f), tuple1, tuple2, std::index_sequence_for{})) { return Imp::transformTupleHelper(std::forward(f), tuple1, tuple2, std::index_sequence_for{}); } namespace Imp { template struct IntegerSequenceTupleHelper {}; template struct IntegerSequenceTupleHelper> { using Type = std::tuple...>; }; } // end namespace Imp /** * \brief Transform integer_sequence to tuple...> */ template using IntegerSequenceTuple= typename Imp::IntegerSequenceTupleHelper::Type; /** * \brief Get last entry of type list * * \ingroup Utility */ template struct LastType { using type = typename std::tuple_element>::type; }; namespace Imp { template struct RotateHelper; template struct RotateHelper, std::index_sequence > { using type = typename std::tuple::type, typename std::tuple_element>::type...>; }; } // end namespace Imp /** * \brief Rotate type list by one, such that last entry is moved to first position * * \ingroup Utility * * The rotated type list is exported as tuple */ template struct RotateTuple { using type = typename Imp::RotateHelper, std::make_index_sequence>::type; }; } // namespace Dune::Functions } // namespace Dune #endif // DUNE_FUNCTIONS_COMMON_UTILITY_HH dune-functions-2.5.1/dune/functions/functionspacebases/000077500000000000000000000000001313314422100232745ustar00rootroot00000000000000dune-functions-2.5.1/dune/functions/functionspacebases/CMakeLists.txt000066400000000000000000000012641313314422100260370ustar00rootroot00000000000000add_subdirectory("test") install(FILES basistags.hh bsplinebasis.hh compositebasis.hh concepts.hh defaultglobalbasis.hh defaultlocalindexset.hh defaultlocalview.hh defaultnodetorangemap.hh flatmultiindex.hh flatvectorbackend.hh hierarchicvectorwrapper.hh interpolate.hh lagrangebasis.hh lagrangedgbasis.hh powerbasis.hh pq1nodalbasis.hh pqknodalbasis.hh nodes.hh sizeinfo.hh subspacebasis.hh subspacelocalview.hh taylorhoodbasis.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/functions/functionspacebases) dune-functions-2.5.1/dune/functions/functionspacebases/basistags.hh000066400000000000000000000076051313314422100256050ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_BASISTAGS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_BASISTAGS_HH #include #include namespace Dune { namespace Functions { namespace Concept { struct IndexMergingStrategy { template auto require(T&& t) -> decltype( registerIndexMergingStrategy(t) ); }; template static constexpr bool isIndexMergingStrategy() { return models(); } template static constexpr bool isIndexMergingStrategy(T&& t) { return models>(); } } // namespace Concept namespace BasisBuilder { /** * \brief Base class for index merging strategies to simplify detection * * \ingroup FunctionSpaceBasesUtilities */ struct IndexMergingStrategy {}; void registerIndexMergingStrategy(IndexMergingStrategy); /** * \brief Lexicographic merging of direct children without blocking. * * \ingroup FunctionSpaceBasesUtilities * * Example: For two children with indices * * {(0,i0), (0,i1), (1,i2)} and {(0,k0), (1,k1), (2,k2)} * * the merged indices will be * * {(0,i0), (0,i1), (1,i2), (2,k0), (3,k1), (4,k2)} */ struct FlatLexicographic : public IndexMergingStrategy {}; /** * \brief Interleaved merging of direct children without blocking. * * \ingroup FunctionSpaceBasesUtilities * * Example: For two children with indices * * {(0,i0), (1,i1), (2,i2)} and {(0,i0), (1,i1), (2,i2)} * * the merged indices will be * * {(0,i0), (2,i1), (4,i2), (1,k0), (3,k1), (5,k2)} */ struct FlatInterleaved : public IndexMergingStrategy {}; /** * \brief Lexicographic merging of direct children with blocking (i.e. creating one block per direct child). * * \ingroup FunctionSpaceBasesUtilities * * Example: For two children with indices * * {(0,i0), (0,i1), (1,i2)} and {(0,k0), (1,k1), (2,k2)} * * the merged indices will be * * {(0,0,i0), (0,0,i1), (0,1,i2), (1,0,k0), (1,1,k1), (1,2,k2)} */ struct BlockedLexicographic : public IndexMergingStrategy {}; /** * \brief Interleaved merging of direct children with blocking (i.e. creating blocks at the leaves containing one leaf per child each). * * \ingroup FunctionSpaceBasesUtilities * * Example: For two children with indices * * {(0,i0), (1,i1), (2,i2)} and {(0,i0), (1,i1), (2,i2)} * * the merged indices will be * * {(0,i0,0), (1,i1,0), (2,i2,0), (0,i0,1), (1,i1,1), (2,i2,1)} */ struct LeafBlockedInterleaved : public IndexMergingStrategy {}; /** * \brief Creates a lexicographic merging of direct children without blocking. * * \ingroup FunctionSpaceBasesUtilities */ constexpr FlatLexicographic flatLexicographic() { return {}; } /** * \brief Creates an interleaved merging of direct children without blocking. * * \ingroup FunctionSpaceBasesUtilities */ constexpr FlatInterleaved flatInterleaved() { return {}; } /** * \brief Creates a lexicographic merging of direct children with blocking (i.e. creating one block per direct child). * * \ingroup FunctionSpaceBasesUtilities */ constexpr BlockedLexicographic blockedLexicographic() { return {}; } /** * \brief Creates an interleaved merging of direct children with blocking (i.e. creating blocks at the leaves containing one leaf per child each). * * \ingroup FunctionSpaceBasesUtilities */ constexpr LeafBlockedInterleaved leafBlockedInterleaved() { return {}; } } // end namespace BasisBuilder } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_BASISTAGS_HH dune-functions-2.5.1/dune/functions/functionspacebases/bsplinebasis.hh000066400000000000000000001341521313314422100263010ustar00rootroot00000000000000#ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_BSPLINEBASIS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_BSPLINEBASIS_HH /** \file * \brief The B-spline global function space basis */ #include /** \todo Don't use this matrix */ #include #include #include #include #include #include #include namespace Dune { namespace Functions { // A maze of dependencies between the different parts of this. We need lots of forward declarations template class BSplineLocalFiniteElement; template class BSplineNodeFactory; /** \brief LocalBasis class in the sense of dune-localfunctions, presenting the restriction * of a B-spline patch to a knot span * * \ingroup FunctionSpaceBasesImplementations * * \tparam GV Grid view that the basis is defined on * \tparam R Number type used for spline function values */ template class BSplineLocalBasis { friend class BSplineLocalFiniteElement; typedef typename GV::ctype D; enum {dim = GV::dimension}; public: //! \brief export type traits for function signature typedef LocalBasisTraits,R,1,Dune::FieldVector, Dune::FieldMatrix, 2> Traits; /** \brief Constructor with a given B-spline patch * * The patch object does all the work. */ BSplineLocalBasis(const BSplineNodeFactory>& nodeFactory, const BSplineLocalFiniteElement& lFE) : nodeFactory_(nodeFactory), lFE_(lFE) {} /** \brief Evaluate all shape functions * \param in Coordinates where to evaluate the functions, in local coordinates of the current knot span */ void evaluateFunction (const FieldVector& in, std::vector >& out) const { FieldVector globalIn = offset_; scaling_.umv(in,globalIn); nodeFactory_.evaluateFunction(globalIn, out, lFE_.currentKnotSpan_); } /** \brief Evaluate Jacobian of all shape functions * \param in Coordinates where to evaluate the Jacobian, in local coordinates of the current knot span */ void evaluateJacobian (const FieldVector& in, std::vector >& out) const { FieldVector globalIn = offset_; scaling_.umv(in,globalIn); nodeFactory_.evaluateJacobian(globalIn, out, lFE_.currentKnotSpan_); for (size_t i=0; i inline void evaluate (const typename Dune::array& directions, const typename Traits::DomainType& in, std::vector& out) const { switch(k) { case 0: evaluateFunction(in, out); break; case 1: { FieldVector globalIn = offset_; scaling_.umv(in,globalIn); nodeFactory_.evaluate(directions, globalIn, out, lFE_.currentKnotSpan_); for (size_t i=0; i globalIn = offset_; scaling_.umv(in,globalIn); nodeFactory_.evaluate(directions, globalIn, out, lFE_.currentKnotSpan_); for (size_t i=0; i>& nodeFactory_; const BSplineLocalFiniteElement& lFE_; // Coordinates in a single knot span differ from coordinates on the B-spline patch // by an affine transformation. This transformation is stored in offset_ and scaling_. FieldVector offset_; DiagonalMatrix scaling_; }; /** \brief Attaches a shape function to an entity * * \ingroup FunctionSpaceBasesImplementations * * The attachment uses the same order as for Qk elements. This does *not* provide sufficient information * to compute global indices for the shape functions. However, it does allow to find all degrees of freedom * that belong to the grid boundary, if the knot vector is open. * * \note Currently only implemented for 1d and 2d grids. For higher dimensions you can still use * the BSplineBasis, but you won't be able to find the degrees of freedom on the grid boundary. * * \tparam dim Dimension of the reference cube */ template class BSplineLocalCoefficients { // Return i as a d-digit number in the (k+1)-nary system std::array multiindex (unsigned int i) const { std::array alpha; for (int j=0; j& subEntity) { if (sizes_[0]==1) { subEntity[0] = 0; return; } /* edge and vertex numbering 0----0----1 */ unsigned lastIndex=0; subEntity[lastIndex++] = 0; // corner 0 for (unsigned i = 0; i < sizes_[0] - 2; ++i) subEntity[lastIndex++] = 0; // inner dofs of element (0) subEntity[lastIndex++] = 1; // corner 1 assert(size()==lastIndex); } void setup2d(std::vector& subEntity) { unsigned lastIndex=0; // LocalKey: entity number , entity codim, dof indices within each entity /* edge and vertex numbering 2----3----3 | | | | 0 1 | | | | 0----2----1 */ // lower edge (2) subEntity[lastIndex++] = 0; // corner 0 for (unsigned i = 0; i < sizes_[0]-2; ++i) subEntity[lastIndex++] = 2; // inner dofs of lower edge (2) subEntity[lastIndex++] = 1; // corner 1 // iterate from bottom to top over inner edge dofs for (unsigned e = 0; e < sizes_[1]-2; ++e) { subEntity[lastIndex++] = 0; // left edge (0) for (unsigned i = 0; i < sizes_[0]-2; ++i) subEntity[lastIndex++] = 0; // face dofs subEntity[lastIndex++] = 1; // right edge (1) } // upper edge (3) subEntity[lastIndex++] = 2; // corner 2 for (unsigned i = 0; i < sizes_[0]-2; ++i) subEntity[lastIndex++] = 3; // inner dofs of upper edge (3) subEntity[lastIndex++] = 3; // corner 3 assert(size()==lastIndex); } public: void init(const std::array& sizes) { sizes_ = sizes; li_.resize(size()); // Set up array of codimension-per-dof-number std::vector codim(li_.size()); for (std::size_t i=0; i mIdx = multiindex(i); for (int j=0; j index(size()); for (std::size_t i=0; i mIdx = multiindex(i); for (int j=dim-1; j>=0; j--) if (mIdx[j]>0 and mIdx[j] subEntity(li_.size()); if (subEntity.size() > 0) { if (dim==1) { setup1d(subEntity); } else if (dim==2 and sizes_[0]>1 and sizes_[1]>1) { setup2d(subEntity); } } for (size_t i=0; i()); } //! get i'th index const LocalKey& localKey (std::size_t i) const { return li_[i]; } private: // Number of shape functions on this element per coordinate direction std::array sizes_; std::vector li_; }; /** \brief Local interpolation in the sense of dune-localfunctions, for the B-spline basis on tensor-product grids * * \ingroup FunctionSpaceBasesImplementations */ template class BSplineLocalInterpolation { public: //! \brief Local interpolation of a function template void interpolate (const F& f, std::vector& out) const { DUNE_THROW(NotImplemented, "BSplineLocalInterpolation::interpolate"); } }; /** \brief LocalFiniteElement in the sense of dune-localfunctions, for the B-spline basis on tensor-product grids * * \ingroup FunctionSpaceBasesImplementations * * This class ties together the implementation classes BSplineLocalBasis, BSplineLocalCoefficients, and BSplineLocalInterpolation * * \tparam D Number type used for domain coordinates * \tparam R Number type used for spline function values * \tparam dim Dimension of the patch */ template class BSplineLocalFiniteElement { typedef typename GV::ctype D; enum {dim = GV::dimension}; friend class BSplineLocalBasis; public: /** \brief Export various types related to this LocalFiniteElement */ typedef LocalFiniteElementTraits, BSplineLocalCoefficients, BSplineLocalInterpolation > > Traits; /** \brief Constructor with a given B-spline basis */ BSplineLocalFiniteElement(const BSplineNodeFactory>& nodeFactory) : nodeFactory_(nodeFactory), localBasis_(nodeFactory,*this) {} /** \brief Bind LocalFiniteElement to a specific knot span of the spline patch * * Elements are the non-empty knot spans, here we do the renumbering * * \param ijk Integer coordinates in the tensor product patch */ void bind(const std::array& elementIdx) { /* \todo In the long run we need to precompute a table for this */ for (size_t i=0; i sizes; for (size_t i=0; i& localBasis() const { return localBasis_; } /** \brief Hand out a LocalCoefficients object */ const BSplineLocalCoefficients& localCoefficients() const { return localCoefficients_; } /** \brief Hand out a LocalInterpolation object */ const BSplineLocalInterpolation >& localInterpolation() const { return localInterpolation_; } /** \brief Number of shape functions in this finite element */ uint size () const { std::size_t r = 1; for (int i=0; i (nodeFactory_.knotVectors_[i].size() - currentKnotSpan_[i] - 2) ) r -= order[i] - (nodeFactory_.knotVectors_[i].size() - currentKnotSpan_[i] - 2); return r; } const BSplineNodeFactory>& nodeFactory_; BSplineLocalBasis localBasis_; BSplineLocalCoefficients localCoefficients_; BSplineLocalInterpolation > localInterpolation_; // The knot span we are bound to std::array currentKnotSpan_; }; template class BSplineNode; template class BSplineNodeIndexSet; /** \brief Node factory for B-spline basis * * \ingroup FunctionSpaceBasesImplementations * * \tparam GV The GridView that the space is defined on * \tparam MI Type to be used for multi-indices * * The BSplineNodeFactory can be used to embed a BSplineBasis * in a larger basis for the construction of product spaces. */ template class BSplineNodeFactory { static const int dim = GV::dimension; /** \brief Simple dim-dimensional multi-index class */ class MultiDigitCounter { public: /** \brief Constructs a new multi-index, and sets all digits to zero * \param limits Number of different digit values for each digit, i.e., digit i counts from 0 to limits[i]-1 */ MultiDigitCounter(const std::array& limits) : limits_(limits) { std::fill(counter_.begin(), counter_.end(), 0); } /** \brief Increment the multi-index */ MultiDigitCounter& operator++() { for (int i=0; i limits_; /** \brief The values of the multi-index. Each array entry is one digit */ std::array counter_; }; public: /** \brief The grid view that the FE space is defined on */ using GridView = GV; using size_type = std::size_t; template using Node = BSplineNode; template using IndexSet = BSplineNodeIndexSet; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = MI; using SizePrefix = Dune::ReservedVector; // Type used for function values using R = double; /** \brief Construct a B-spline basis for a given grid view and set of knot vectors * * The grid *must* match the knot vectors, i.e.: * - The grid must be structured and Cartesian, and have cube elements only * - The number of elements in each direction must match the number of knot spans in that direction * - In fact, the element spacing in any direction must match the knot spacing in that direction * (disregarding knot multiplicities) * - When ordering the grid elements according to their indices, the resulting order must * be lexicographical, with the x-index increasing fastest. * * Unfortunately, not all of these conditions can be checked for automatically. * * \param knotVector A single knot vector, which will be used for all coordinate directions * \param order B-spline order, will be used for all coordinate directions * \param makeOpen If this is true, then knots are prepended and appended to the knot vector to make the knot vector 'open'. * i.e., start and end with 'order+1' identical knots. Basis functions from such knot vectors are interpolatory at * the end of the parameter interval. */ BSplineNodeFactory(const GridView& gridView, const std::vector& knotVector, unsigned int order, bool makeOpen = true) : gridView_(gridView) { // \todo Detection of duplicate knots std::fill(elements_.begin(), elements_.end(), knotVector.size()-1); // Mediocre sanity check: we don't know the number of grid elements in each direction. // but at least we know the total number of elements. assert( std::accumulate(elements_.begin(), elements_.end(), 1, std::multiplies()) == gridView_.size(0) ); for (int i=0; i& lowerLeft, const FieldVector& upperRight, const array& elements, unsigned int order, bool makeOpen = true) : elements_(elements), gridView_(gridView) { // Mediocre sanity check: we don't know the number of grid elements in each direction. // but at least we know the total number of elements. assert( std::accumulate(elements_.begin(), elements_.end(), 1, std::multiplies()) == gridView_.size(0) ); for (int i=0; i Node node(const TP& tp) const { return Node{tp,this}; } /** * \brief Create tree node index set with given root tree path * * \tparam TP Type of root tree path * \param tp Root tree path * * Create an index set suitable for the tree node obtained * by node(tp). */ template IndexSet indexSet() const { return IndexSet{*this}; } //! Return number of possible values for next position in multi index size_type size(const SizePrefix prefix) const { if (prefix.size() == 0) return size(); assert(false); } //! Get the total dimension of the space spanned by this basis size_type dimension() const { return size(); } //! Get the maximal number of DOFs associated to node for any element size_type maxNodeSize() const { size_type result = 1; for (int i=0; i& in, std::vector >& out, const std::array& currentKnotSpan) const { // Evaluate Dune::array, dim> oneDValues; for (size_t i=0; i limits; for (int i=0; i& in, std::vector >& out, const std::array& currentKnotSpan) const { // How many shape functions to we have in each coordinate direction? std::array limits; for (int i=0; i (knotVectors_[i].size() - currentKnotSpan[i] - 2) ) limits[i] -= order_[i] - (knotVectors_[i].size() - currentKnotSpan[i] - 2); } // The lowest knot spans that we need values from std::array offset; for (int i=0; i, dim> oneDValues; // Evaluate 1d function values of one order lower (needed for the derivative formula) Dune::array, dim> lowOrderOneDValues; Dune::array, dim> values; for (size_t i=0; i, dim> oneDDerivatives; for (size_t i=0; i, dim> oneDValuesShort; for (int i=0; i void evaluate(const typename std::array& directions, const FieldVector& in, std::vector >& out, const std::array& currentKnotSpan) const { if (k != 1 && k != 2) DUNE_THROW(RangeError, "Differentiation order greater than 2 is not supported!"); // Evaluate 1d function values (needed for the product rule) std::array, dim> oneDValues; std::array, dim> oneDDerivatives; std::array, dim> oneDSecondDerivatives; // Evaluate 1d function derivatives if (k==1) for (size_t i=0; i offset; for (int i=0; i limits; for (int i=0; i (knotVectors_[i].size() - currentKnotSpan[i] - 2) ) limits[i] -= order_[i] - (knotVectors_[i].size() - currentKnotSpan[i] - 2); } // Working towards computing only the parts that we really need: // Let's copy them out into a separate array std::array, dim> oneDValuesShort; for (int i=0; i getIJK(typename GridView::IndexSet::IndexType idx, std::array elements) { std::array result; for (int i=0; i& out, const std::vector& knotVector, unsigned int order, unsigned int currentKnotSpan) { std::size_t outSize = order+1; // The 'standard' value away from the boundaries of the knot vector if (currentKnotSpan (knotVector.size() - currentKnotSpan - 2) ) outSize -= order - (knotVector.size() - currentKnotSpan - 2); out.resize(outSize); // It's not really a matrix that is needed here, a plain 2d array would do DynamicMatrix N(order+1, knotVector.size()-1); // The text books on splines use the following geometric condition here to fill the array N // (see for example Cottrell, Hughes, Bazilevs, Formula (2.1). However, this condition // only works if splines are never evaluated exactly on the knots. // // for (size_t i=0; i 1e-10) ? (in - knotVector[i]) / (knotVector[i+r] - knotVector[i]) : 0; R factor2 = ((knotVector[i+r+1] - knotVector[i+1]) > 1e-10) ? (knotVector[i+r+1] - in) / (knotVector[i+r+1] - knotVector[i+1]) : 0; N[r][i] = factor1 * N[r-1][i] + factor2 * N[r-1][i+1]; } /** \todo We only hand out function values for those basis functions whose support overlaps * the current knot span. However, in the preceding loop we still computed _all_ values_. * This won't scale. */ for (size_t i=0; i& out, const std::vector& knotVector, unsigned int order, unsigned int currentKnotSpan) { // It's not really a matrix that is needed here, a plain 2d array would do DynamicMatrix& N = out; N.resize(order+1, knotVector.size()-1); // The text books on splines use the following geometric condition here to fill the array N // (see for example Cottrell, Hughes, Bazilevs, Formula (2.1). However, this condition // only works if splines are never evaluated exactly on the knots. // // for (size_t i=0; i 1e-10) ? (in - knotVector[i]) / (knotVector[i+r] - knotVector[i]) : 0; R factor2 = ((knotVector[i+r+1] - knotVector[i+1]) > 1e-10) ? (knotVector[i+r+1] - in) / (knotVector[i+r+1] - knotVector[i+1]) : 0; N[r][i] = factor1 * N[r-1][i] + factor2 * N[r-1][i+1]; } } /** \brief Evaluate the second derivatives of all one-dimensional B-spline functions for a given coordinate direction * * \param in Scalar(!) coordinate where to evaluate the functions * \param enableEvaluations switches calculation of desired derivatives on * \param [out] out Vector containing the values of all B-spline derivatives at 'in' * \param [out] outJac Vector containing the first derivatives of all B-spline derivatives at 'in' (only if calculation was switched on by enableEvaluations) * \param [out] outHess Vector containing the second derivatives of all B-spline derivatives at 'in' (only if calculation was switched on by enableEvaluations) */ static void evaluateAll(const typename GV::ctype& in, std::vector& out, bool evaluateJacobian, std::vector& outJac, bool evaluateHessian, std::vector& outHess, const std::vector& knotVector, unsigned int order, unsigned int currentKnotSpan) { // How many shape functions to we have in each coordinate direction? unsigned int limit; limit = order+1; // The 'standard' value away from the boundaries of the knot vector if (currentKnotSpan (knotVector.size() - currentKnotSpan - 2) ) limit -= order - (knotVector.size() - currentKnotSpan - 2); // The lowest knot spans that we need values from unsigned int offset; offset = std::max((int)(currentKnotSpan - order),0); // Evaluate 1d function values (needed for the product rule) DynamicMatrix values; evaluateFunctionFull(in, values, knotVector, order, currentKnotSpan); out.resize(knotVector.size()-order-1); for (size_t j=0; j lowOrderOneDValues; if (order!=0) { lowOrderOneDValues.resize(knotVector.size()-(order-1)-1); for (size_t j=0; j lowOrderTwoDValues; if (order>1 && evaluateHessian) { lowOrderTwoDValues.resize(knotVector.size()-(order-2)-1); for (size_t j=0; j order_; /** \brief The knot vectors, one for each space dimension */ array, dim> knotVectors_; /** \brief Number of grid elements in the different coordinate directions */ std::array elements_; GridView gridView_; }; template class BSplineNode : public LeafBasisNode { static const int dim = GV::dimension; using Base = LeafBasisNode; public: using size_type = std::size_t; using TreePath = TP; using Element = typename GV::template Codim<0>::Entity; using FiniteElement = BSplineLocalFiniteElement; BSplineNode(const TreePath& treePath, const BSplineNodeFactory>* nodeFactory) : Base(treePath), nodeFactory_(nodeFactory), finiteElement_(*nodeFactory) {} //! Return current element, throw if unbound const Element& element() const { return element_; } /** \brief Return the LocalFiniteElement for the element we are bound to * * The LocalFiniteElement implements the corresponding interfaces of the dune-localfunctions module */ const FiniteElement& finiteElement() const { return finiteElement_; } //! Bind to element. void bind(const Element& e) { element_ = e; auto elementIndex = nodeFactory_->gridView().indexSet().index(e); finiteElement_.bind(nodeFactory_->getIJK(elementIndex,nodeFactory_->elements_)); this->setSize(finiteElement_.size()); } protected: const BSplineNodeFactory>* nodeFactory_; FiniteElement finiteElement_; Element element_; }; template class BSplineNodeIndexSet { enum {dim = GV::dimension}; public: using size_type = std::size_t; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = MI; using NodeFactory = BSplineNodeFactory; using Node = typename NodeFactory::template Node; BSplineNodeIndexSet(const NodeFactory& nodeFactory) : nodeFactory_(&nodeFactory) {} /** \brief Bind the view to a grid element * * Having to bind the view to an element before being able to actually access any of its data members * offers to centralize some expensive setup code in the 'bind' method, which can save a lot of run-time. */ void bind(const Node& node) { node_ = &node; // Local degrees of freedom are arranged in a lattice. // We need the lattice dimensions to be able to compute lattice coordinates from a local index for (int i=0; ifiniteElement().size(i); } /** \brief Unbind the view */ void unbind() { node_ = nullptr; } /** \brief Size of subtree rooted in this node (element-local) */ size_type size() const { return node_->finiteElement().size(); } //! Maps from subtree index set [0..size-1] to a globally unique multi index in global basis MultiIndex index(size_type i) const { std::array localIJK = nodeFactory_->getIJK(i, localSizes_); const auto currentKnotSpan = node_->finiteElement().currentKnotSpan_; const auto order = nodeFactory_->order_; std::array globalIJK; for (int i=0; i=0; i--) globalIdx = globalIdx * nodeFactory_->size(i) + globalIJK[i]; return { globalIdx }; } protected: const NodeFactory* nodeFactory_; const Node* node_; std::array localSizes_; }; // ***************************************************************************** // This is the actual global basis implementation based on the reusable parts. // ***************************************************************************** /** \brief A global B-spline basis * * \ingroup FunctionSpaceBasesImplementations * * \tparam GV The GridView that the space is defined on */ template using BSplineBasis = DefaultGlobalBasis> >; } // namespace Functions } // namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_BSPLINEBASIS_HH dune-functions-2.5.1/dune/functions/functionspacebases/compositebasis.hh000066400000000000000000000361071313314422100266500ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_COMPOSITEBASIS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_COMPOSITEBASIS_HH #include #include #include #include #include #include #include #include #include #include #include #include namespace Dune { namespace Functions { namespace Imp { template struct SizeOf : public std::integral_constant {}; template using index_sequence_for = std::make_index_sequence{}>; } // ***************************************************************************** // This is the reusable part of the composite bases. It contains // // CompositeNodeFactory // CompositeNodeIndexSet // // The factory allows to create the others and is the owner of possible shared // state. These components do _not_ depend on the global basis or index // set and can be used without a global basis. // ***************************************************************************** template class CompositeNodeIndexSet; /** * \brief A factory for composite bases * * \ingroup FunctionSpaceBasesImplementations * * This node factory represente a composition of several given node factories. * Its node type is a CompositeBasisNodes for the given subnodes. * * \tparam MI Type to be used for global multi-indices * \tparam IMS An IndexMergingStrategy used to merge the global indices of the child factories * \tparam SF The child factories */ template class CompositeNodeFactory { public: //! Tuple of child factories using SubFactories = std::tuple; //! The grid view that the FE basis is defined on using GridView = typename std::tuple_element<0, SubFactories>::type::GridView; //! Type used for indices and size information using size_type = std::size_t; //! Strategy used to merge the global indices of the child factories using IndexMergingStrategy = IMS; protected: static const std::size_t children = sizeof...(SF); template friend class CompositeNodeIndexSet; using ChildIndexTuple = IntegerSequenceTuple>; template struct FixedTP { template using IndexToSubTreePath = decltype(TypeTree::push_back(TP(), I())); using SubTreePaths = TransformTuple; template using FactoryToSubNode = typename F::template Node; using SubNodes = TransformTuple; template using FactoryToSubIndexSet = typename F::template IndexSet; using SubIndexSets = TransformTuple; template using SubNodesToNode = CompositeBasisNode; using Node = ExpandTuple; }; public: //! Template mapping index of child to its factory type template using SubFactory = typename std::tuple_element>::type; //! Template mapping root tree path to type of created tree node template using Node = typename FixedTP::Node; //! Template mapping root tree path to type of created tree node index set template using IndexSet = CompositeNodeIndexSet; //! Type used for global numbering of the basis vectors using MultiIndex = MI; //! Type used for prefixes handed to the size() method using SizePrefix = Dune::ReservedVector; /** * \brief Constructor for given child factory objects * * The child factories will be stored as copies */ template = 0, enableIfConstructible, SFArgs...> = 0> CompositeNodeFactory(SFArgs&&... sfArgs) : subFactories_(std::forward(sfArgs)...) { } //! Initialize the global indices void initializeIndices() { using namespace Dune::Hybrid; forEach(Dune::Std::make_index_sequence(), [&](auto i) { elementAt(subFactories_, i).initializeIndices(); }); } //! Obtain the grid view that the basis is defined on const GridView& gridView() const { return std::get<0>(subFactories_).gridView(); } //! Update the stored grid view, to be called if the grid has changed void update(const GridView& gv) { using namespace Dune::Hybrid; forEach(Dune::Std::make_index_sequence(), [&](auto i) { elementAt(subFactories_, i).update(gv); }); } /** * \brief Create tree node with given root tree path * * \tparam TP Type of root tree path * \param tp Root tree path * * By passing a non-trivial root tree path this can be used * to create a node suitable for being placed in a tree at * the position specified by the root tree path. */ template Node node(const TP& tp) const { auto node = Node(tp); using namespace Dune::Hybrid; forEach(Dune::Std::make_index_sequence(), [&](auto i) { node.setChild( elementAt(subFactories_, i).node(TypeTree::push_back(tp, i)), i); }); return node; } /** * \brief Create tree node index set with given root tree path * * \tparam TP Type of root tree path * \param tp Root tree path * * Create an index set suitable for the tree node obtained * by node(tp). */ template IndexSet indexSet() const { return IndexSet{*this}; } //! Same as size(prefix) with empty prefix size_type size() const { return size({}); } //! Return number of possible values for next position in multi index size_type size(const SizePrefix& prefix) const { return size(prefix, IndexMergingStrategy{}); } private: size_type size(const SizePrefix& prefix, BasisBuilder::BlockedLexicographic) const { if (prefix.size() == 0) return children; return Hybrid::switchCases(std::make_index_sequence(), prefix[0], [&] (auto i) { const auto& subFactory = std::get(subFactories_); typename std::decay::type::SizePrefix subPrefix; for(std::size_t i=1; i size_type operator()(const I&, const SFT& subFactories, const SizePrefix& prefix, size_type& shiftedFirst, size_type& r) { using SubFactory = typename std::tuple_element::type; const SubFactory& subFactory = std::get(subFactories); if (shiftedFirst < subFactory.size()) { typename SubFactory::SizePrefix subPrefix; subPrefix.push_back(shiftedFirst); for(std::size_t i=1; i(), [&](auto i) { r += elementAt(subFactories_, i).size(); }); else { size_type shiftedFirst = prefix[0]; staticFindInRange<0, sizeof...(SF)>(Lambda_size_flat_sizeInSubtree(), subFactories_, prefix, shiftedFirst, r); } return r; } public: //! Get the total dimension of the space spanned by this basis size_type dimension() const { size_type r=0; // Accumulate dimension() for all subfactories using namespace Dune::Hybrid; forEach(Dune::Std::make_index_sequence(), [&](auto i) { r += elementAt(subFactories_, i).dimension(); }); return r; } //! Get the maximal number of DOFs associated to node for any element size_type maxNodeSize() const { size_type r=0; // Accumulate maxNodeSize() for all subfactories using namespace Dune::Hybrid; forEach(Dune::Std::make_index_sequence(), [&](auto i) { r += elementAt(subFactories_, i).maxNodeSize(); }); return r; } protected: std::tuple subFactories_; }; template class CompositeNodeIndexSet { static const std::size_t children = sizeof...(SF); public: template using SubFactory = typename std::tuple_element>::type; using GridView = typename SubFactory<0>::GridView; using size_type = std::size_t; using IndexMergingStrategy = IMS; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = MI; using NodeFactory = CompositeNodeFactory; using Node = typename NodeFactory::template Node; using SubTreePaths = typename NodeFactory::template FixedTP::SubTreePaths; using SubIndexSets = typename NodeFactory::template FixedTP::SubIndexSets; struct Lambda_FactoryToSubIndexSet { // transform a single (factory,subTreePath) pair to subIndexSet template auto operator()(const Factory& factory, const SubTP& subTP) ->decltype(factory.template indexSet()) { return factory.template indexSet(); } }; CompositeNodeIndexSet(const NodeFactory & nodeFactory) : nodeFactory_(&nodeFactory), subNodeIndexSetTuple_(transformTuple(Lambda_FactoryToSubIndexSet(), nodeFactory_->subFactories_, SubTreePaths())) {} void bind(const Node& node) { node_ = &node; using namespace Dune::Hybrid; forEach(Dune::Std::make_index_sequence(), [&](auto i) { elementAt(subNodeIndexSetTuple_, i).bind(node.child(i)); }); } void unbind() { node_ = nullptr; using namespace Dune::Hybrid; forEach(Dune::Std::make_index_sequence(), [&](auto i) { elementAt(subNodeIndexSetTuple_, i).unbind(); }); } size_type size() const { return node_->size(); } MultiIndex index(size_type localIndex) const { return index(localIndex, IndexMergingStrategy{}); } struct Lambda_index_flat { template bool operator()(const I& i, SNIT& subNodeIndexSetTuple, const SFT& subFactories, size_type localIndex, size_type& rootOffset, MultiIndex& multiIndex) { const auto& subNodeIndexSet = std::get(subNodeIndexSetTuple); size_type size = subNodeIndexSet.size(); if (localIndex < size) { multiIndex = subNodeIndexSet.index(localIndex); multiIndex[0] += rootOffset; return true; } localIndex -= size; rootOffset += std::get(subFactories).size(); return false; } }; MultiIndex index(const size_type& localIndex, BasisBuilder::FlatLexicographic) const { size_type shiftedLocalIndex = localIndex; size_type rootOffset = 0; MultiIndex mi; staticFindInRange<0, sizeof...(SF)>(Lambda_index_flat(), subNodeIndexSetTuple_, nodeFactory_->subFactories_, shiftedLocalIndex, rootOffset, mi); return mi; } struct Lambda_index { template bool operator()(const I& i, SNIT& subNodeIndexSetTuple, size_type& localIndex, size_type& component, MultiIndex& multiIndex) { const auto& subNodeIndexSet = std::get(subNodeIndexSetTuple); size_type size = subNodeIndexSet.size(); if (localIndex < size) { multiIndex = subNodeIndexSet.index(localIndex); component = i; return true; } localIndex -= size; return false; } }; MultiIndex index(const size_type& localIndex, BasisBuilder::BlockedLexicographic) const { size_type shiftedLocalIndex = localIndex; size_type component = 0; MultiIndex mi; staticFindInRange<0, sizeof...(SF)>(Lambda_index(), subNodeIndexSetTuple_, shiftedLocalIndex, component, mi); mi.resize(mi.size()+1); for(std::size_t i=mi.size()-1; i>0; --i) mi[i] = mi[i-1]; mi[0] = component; return mi; } private: const NodeFactory* nodeFactory_; SubIndexSets subNodeIndexSetTuple_; const Node* node_; }; namespace BasisBuilder { namespace Imp { template constexpr std::size_t maxHelper(ST0&& i0) { return i0; } template constexpr std::size_t maxHelper(ST0&& i0, ST&&... i) { return (i0 > maxHelper(i...)) ? i0 : maxHelper(i...); } template struct CompositeNodeFactoryBuilder { static const bool isBlocked = std::is_same::value or std::is_same::value; static const std::size_t requiredMultiIndexSize=maxHelper(SubFactoryTags::requiredMultiIndexSize...) + (std::size_t)(isBlocked); template auto build(const GridView& gridView) -> CompositeNodeFactory(gridView))...> { return {SubFactoryTags().template build(gridView)...}; } }; template auto compositeImp(std::tuple) -> Imp::CompositeNodeFactoryBuilder { return {}; } } // end namespace BasisBuilder::Imp /** * \brief Create a factory builder that can build a CompositeNodeFactory * * \ingroup FunctionSpaceBasesImplementations * * \tparam Args Types of child factory builders and IndexMergingStrategy type * \param args Child factory builder objects and an IndexMergingStrategy * * This is the overload used if the last argument is an IndexMergingStrategy. */ template< typename... Args, std::enable_if_t::type>(),int> = 0> auto composite(Args&&... args) { return Imp::compositeImp(typename RotateTuple::type{}); } /** * \brief Create a factory builder that can build a CompositeNodeFactory * * \ingroup FunctionSpaceBasesImplementations * * \tparam Args Types of child factory builders * \param args Child factory builder objects * * This is the overload used if no IndexMergingStrategy is supplied. * In this case the BasisBuilder::BlockedLexicographic strategy is used. */ template< typename... Args, std::enable_if_t::type>(),int> = 0> auto composite(Args&&... args) { return Imp::compositeImp(std::tuple{}); } } // end namespace BasisBuilder } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_COMPOSITEBASIS_HH dune-functions-2.5.1/dune/functions/functionspacebases/concepts.hh000066400000000000000000000205661313314422100254440ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_CONCEPTS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_CONCEPTS_HH #include #include #include namespace Dune { namespace Functions { namespace Concept { using namespace Dune::Concept; struct HasResize { template auto require(C&& c) -> decltype( c.resize(0) ); }; struct HasSizeMethod { template auto require(C&& c) -> decltype( c.size() ); }; struct HasIndexAccess { template auto require(C&& c, I&& i) -> decltype( c[i] ); }; // Concept for a BasisNode in a local ansatz tree struct BasisNode { template auto require(const N& node) -> decltype( requireType(), requireType(), requireConvertible(node.size()), requireConvertible(node.offset()), requireConvertible(node.localIndex(std::declval())), requireConvertible(node.treeIndex()), requireConvertible(node.treePath()), requireBaseOf, N>() ); }; // Concept for a LeafBasisNode in a local ansatz tree template struct LeafBasisNode : Refines { template auto require(const N& node) -> decltype( requireType(), requireType(), requireConvertible(node.element()), requireConvertible(node.finiteElement()), requireConvertible(*(std::declval().template begin<0>())), requireBaseOf, N>() ); }; template struct BasisTree; // Concept for a PowerBasisNode in a local ansatz tree template struct PowerBasisNode : Refines { template auto require(const N& node) -> decltype( requireBaseOf, N>(), requireConcept, typename N::ChildType>() ); }; // Concept for a CompositeBasisNode in a local ansatz tree template struct CompositeBasisNode : Refines { template struct FixArgs { template using CompositeBasisNode = typename Dune::Functions::CompositeBasisNode; }; template auto require(const N& node) -> decltype( requireBaseOf::template CompositeBasisNode, typename N::ChildTypes>, N>(), requireConceptForTupleEntries, typename N::ChildTypes>() ); }; // Concept for a full local BasisTree template struct BasisTree : Refines { template auto require(const N& node) -> decltype( requireConcept, BasisNode>::type, N>(), requireConcept, BasisNode>::type, N>(), requireConcept, BasisNode>::type, N>() ); }; // Concept for a NodeIndexSet template struct NodeIndexSet { template auto require(const I& indexSet) -> decltype( requireType(), requireType(), requireType(), requireType(), requireSameType(), const_cast(indexSet).bind(std::declval()), const_cast(indexSet).unbind(), requireConvertible(indexSet.size()), requireConvertible(indexSet.index(std::declval())) ); }; // Concept for a NodeFactory template struct NodeFactory { using RootTreePath = decltype(TypeTree::hybridTreePath()); template auto require(const F& factory) -> decltype( requireType(), requireType(), requireType(), requireType(), requireType>(), requireType>(), requireSameType(), const_cast(factory).initializeIndices(), requireConvertible(factory.gridView()), requireConvertible>(factory.node(RootTreePath())), requireConvertible>(factory.template indexSet()), requireConvertible(factory.size()), requireConvertible(factory.size(std::declval())), requireConvertible(factory.dimension()), requireConvertible(factory.maxNodeSize()), requireConcept>(factory.node(RootTreePath())), requireConcept>(factory.template indexSet()) ); }; // Concept for a LocalView template struct LocalView { template auto require(const V& localView) -> decltype( requireType(), requireType(), requireType(), requireType(), requireType(), requireSameType(), requireSameType(), requireSameType(), requireSameType::Entity>(), const_cast(localView).bind(std::declval()), const_cast(localView).unbind(), requireConvertible(localView.tree()), requireConvertible(localView.size()), requireConvertible(localView.maxSize()), requireConvertible(localView.globalBasis()), requireConcept>(localView.tree()), 0 ); }; // Concept for a LocalIndexSet template struct LocalIndexSet { template auto require(const I& indexSet) -> decltype( requireType(), requireType(), requireType(), requireSameType(), const_cast(indexSet).bind(std::declval()), const_cast(indexSet).unbind(), requireConvertible(indexSet.size()), requireConvertible(indexSet.index(std::declval())), requireConvertible(indexSet.localView()) ); }; // Concept for a GlobalBasis template struct GlobalBasis { template auto require(const B& basis) -> decltype( requireType(), requireType(), requireType(), requireType(), requireType(), requireType(), requireSameType(), requireConvertible(basis.gridView()), requireConvertible(basis.localIndexSet()), requireConvertible(basis.localView()), requireConvertible(basis.size()), requireConvertible(basis.size(std::declval())), requireConvertible(basis.dimension()), requireConcept>(basis.localIndexSet()), requireConcept>(basis.localView()) ); }; } // namespace Dune::Functions::Concept } // namespace Dune::Functions } // namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_CONCEPTS_HH dune-functions-2.5.1/dune/functions/functionspacebases/defaultglobalbasis.hh000066400000000000000000000130301313314422100274410ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTGLOBALBASIS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTGLOBALBASIS_HH #include #include #include #include #include #include #include namespace Dune { namespace Functions { /** * \brief Global basis for given node factory * * This class implements the interface of a global basis * using the details from a given node factory. Hence * it serves as an example for this interface. * * If you want to implement your own global basis, it may be * better to implement a node factory instead. On the one hand * this needs less boiler-plate code. On the other hand * it makes your implementation composable and thus much * more flexible. That is, you can reuse your factory * as one part in a larger product space by plugging it * e.g. into a CompositeNodeFactory of PowerNodeFactory. * The actual global basis for your FooNodeFactory is * then obtained by using DefaultGlobalBasis. * * \tparam NF Node factory providing the implementation details */ template class DefaultGlobalBasis { public: //! Node factory providing the implementation details using NodeFactory = NF; //! The empty prefix path that identifies the root in the local ansatz tree using PrefixPath = TypeTree::HybridTreePath<>; //! The grid view that the FE space is defined on using GridView = typename NodeFactory::GridView; //! Type used for global numbering of the basis vectors using MultiIndex = typename NodeFactory::MultiIndex; //! Type used for indices and size information using size_type = std::size_t; //! Type of the local view on the restriction of the basis to a single element using LocalView = DefaultLocalView>; //! Node index set provided by NodeFactory using NodeIndexSet = typename NodeFactory::template IndexSet; //! Type used for prefixes handed to the size() method using SizePrefix = typename NodeFactory::SizePrefix; //! Type of local indixes set exported by localIndexSet() using LocalIndexSet = DefaultLocalIndexSet; /** * \brief Constructor * * \tparam T Argument list for NodeFactory * \param t Argument list for NodeFactory * * This will forward all arguments to the constructor of NodeFactory */ template = 0, enableIfConstructible = 0> DefaultGlobalBasis(T&&... t) : nodeFactory_(std::forward(t)...), prefixPath_() { static_assert(models, NodeFactory>(), "Type passed to DefaultGlobalBasis does not model the NodeFactory concept."); nodeFactory_.initializeIndices(); } //! Obtain the grid view that the basis is defined on const GridView& gridView() const { return nodeFactory_.gridView(); } //! Obtain the node factory providing the implementation details const NodeFactory& nodeFactory() const { return nodeFactory_; } /** * \brief Update the stored grid view * * This will update the indexing information of the global basis. * It must be called if the grid has changed. */ void update(const GridView & gv) { nodeFactory_.update(gv); nodeFactory_.initializeIndices(); } //! Get the total dimension of the space spanned by this basis size_type dimension() const { return nodeFactory_.dimension(); } //! Return number of possible values for next position in empty multi index size_type size() const { return nodeFactory_.size(); } //! Return number of possible values for next position in multi index size_type size(const SizePrefix& prefix) const { return nodeFactory_.size(prefix); } //! Return local view for basis LocalView localView() const { return LocalView(*this); } //! Return local index set for basis LocalIndexSet localIndexSet() const { return LocalIndexSet(nodeFactory_.template indexSet()); } //! Return *this because we are not embedded in a larger basis const DefaultGlobalBasis& rootBasis() const { return *this; } //! Return empty path, because this is the root in the local ansatz tree const PrefixPath& prefixPath() const { return prefixPath_; } protected: NodeFactory nodeFactory_; PrefixPath prefixPath_; }; namespace BasisBuilder { template auto makeBasis(const GridView& gridView, FactoryTag&& factoryTag) -> DefaultGlobalBasis >(gridView))> { using MultiIndex = typename Dune::ReservedVector; return {factoryTag.template build(gridView)}; } template auto makeBasis(const GridView& gridView, FactoryTag&& factoryTag) -> DefaultGlobalBasis(gridView))> { return {factoryTag.template build(gridView)}; } } // end namespace BasisBuilder } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTGLOBALBASIS_HH dune-functions-2.5.1/dune/functions/functionspacebases/defaultlocalindexset.hh000066400000000000000000000036621313314422100300270ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTLOCALINDEXSET_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTLOCALINDEXSET_HH #include namespace Dune { namespace Functions { template class DefaultLocalIndexSet { public: using LocalView = LV; using NodeIndexSet = NIS; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = typename NodeIndexSet::MultiIndex; using size_type = std::size_t; DefaultLocalIndexSet(const NodeIndexSet& nodeIndexSet) : nodeIndexSet_(nodeIndexSet) {} DefaultLocalIndexSet(NodeIndexSet&& nodeIndexSet) : nodeIndexSet_(nodeIndexSet) {} /** \brief Bind the index set to a LocalView */ void bind(const LocalView& localView) { localView_ = &localView; nodeIndexSet_.bind(localView_->tree()); } /** \brief Bind the index set to a SubspaceLocalView */ template void bind(const SubspaceLocalView& subspaceLocalView) { bind(subspaceLocalView.rootLocalView()); } /** \brief Unbind the view */ void unbind() { localView_ = nullptr; nodeIndexSet_.unbind(); } /** \brief Size of subtree rooted in this node (element-local) */ size_type size() const { return nodeIndexSet_.size(); } //! Maps from subtree index set [0..size-1] to a globally unique multi index in global basis MultiIndex index(size_type i) const { return nodeIndexSet_.index(i); } /** \brief Return the local view that we are attached to */ const LocalView& localView() const { return *localView_; } protected: const LocalView* localView_; NodeIndexSet nodeIndexSet_; }; } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTLOCALINDEXSET_HH dune-functions-2.5.1/dune/functions/functionspacebases/defaultlocalview.hh000066400000000000000000000061301313314422100271470ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTLOCALVIEW_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTLOCALVIEW_HH #include #include #include namespace Dune { namespace Functions { /** \brief The restriction of a finite element basis to a single element */ template class DefaultLocalView { using PrefixPath = TypeTree::HybridTreePath<>; public: //! The global FE basis that this is a view on using GlobalBasis = GB; //! The grid view the global FE basis lives on using GridView = typename GlobalBasis::GridView; //! Type of the grid element we are bound to using Element = typename GridView::template Codim<0>::Entity; //! The type used for sizes using size_type = std::size_t; //! Tree of local finite elements / local shape function sets using Tree = typename GlobalBasis::NodeFactory::template Node; /** \brief Construct local view for a given global finite element basis */ DefaultLocalView(const GlobalBasis& globalBasis) : globalBasis_(&globalBasis), tree_(globalBasis_->nodeFactory().node(PrefixPath())) { static_assert(models, Tree>(), "Tree type passed to DefaultLocalView does not model the BasisNode concept."); initializeTree(tree_); } /** \brief Bind the view to a grid element * * Having to bind the view to an element before being able to actually access any of its data members * offers to centralize some expensive setup code in the 'bind' method, which can save a lot of run-time. */ void bind(const Element& e) { element_ = e; bindTree(tree_, element_); } /** \brief Return the grid element that the view is bound to * * \throws Dune::Exception if the view is not bound to anything */ const Element& element() const { return element_; } /** \brief Unbind from the current element * * Calling this method should only be a hint that the view can be unbound. */ void unbind() {} /** \brief Return the local ansatz tree associated to the bound entity * * \returns Tree // This is tree */ const Tree& tree() const { return tree_; } /** \brief Total number of degrees of freedom on this element */ size_type size() const { return tree_.size(); } /** * \brief Maximum local size for any element on the GridView * * This is the maximal size needed for local matrices * and local vectors, i.e., the result is */ size_type maxSize() const { return globalBasis_->nodeFactory().maxNodeSize(); } /** \brief Return the global basis that we are a view on */ const GlobalBasis& globalBasis() const { return *globalBasis_; } const DefaultLocalView& rootLocalView() const { return *this; } protected: const GlobalBasis* globalBasis_; Element element_; Tree tree_; }; } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTLOCALVIEW_HH dune-functions-2.5.1/dune/functions/functionspacebases/defaultnodetorangemap.hh000066400000000000000000000071531313314422100301730ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTNODETORANGEMAP_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTNODETORANGEMAP_HH #include #include #include #include namespace Dune { namespace Functions { /** * \brief A simple node to range map using lexicographic ordering * * On construction this map is provided with an ansatz subtree * of the tree in an actual basis. The operator() then maps a * a pair (node,y) of a leaf node in this subtree and an object * y of type range to y[i] where i is the lexicographic index * of the node in the subtree. * * This allows to assoziate each leaf node in the subtree * with a component in the range type which is necessary * when interpolating a vector field into a nontrivial * subtree. * * Notice that the lexicographic index is only computed * wrt the leaf nodes. */ template struct DefaultNodeToRangeMap { // A simple visitor for computing lexicographic // subtree indices. To identify a leaf node // we use its treeIndex() which is unique // wrt the whole tree and store the computed // index in a vector indexed by the tree indices. struct Visitor : public TypeTree::TreeVisitor , public TypeTree::DynamicTraversal { Visitor(std::vector& indices) : indices_(indices), counter_(0) {} template void leaf(Node& node, TreePath treePath) { if (indices_.size() < node.treeIndex()+1) indices_.resize(node.treeIndex()+1); indices_[node.treeIndex()] = counter_; ++counter_; } std::vector& indices_; std::size_t counter_; }; /** * \brief Construct DefaultNodeToRangeMap * * \param tree The tree needed to initialize the map * * This only uses tree.treeIndex() such that the * tree can be in unbound state. Furthermore * no reference or pointer to the tree is stored * and passing a temporary is OK here. */ DefaultNodeToRangeMap(const Tree& tree) { TypeTree::applyToTree(tree, Visitor(indices_)); } template().treeIndex())>() and not Tree::isLeaf, int>::type = 0> auto operator()(const Node& node, Range&& y) const -> decltype(y[0]) { return y[indices_[node.treeIndex()]]; } template().treeIndex())>() or Tree::isLeaf, int>::type = 0> auto operator()(const Node& node, Range&& y) const -> decltype(std::forward(y)) { return std::forward(y); } std::vector indices_; std::size_t counter_; }; template DefaultNodeToRangeMap makeDefaultNodeToRangeMap(const Tree& tree) { return DefaultNodeToRangeMap(tree); } template auto makeDefaultNodeToRangeMap(const Basis& basis, TreePath&& treePath) -> decltype(makeDefaultNodeToRangeMap(TypeTree::child(basis.localView().tree(),treePath))) { auto&& localView = basis.localView(); localView.bind(*basis.gridView().template begin<0>()); auto&& tree = TypeTree::child(localView.tree(),treePath); return makeDefaultNodeToRangeMap(tree); } } // namespace Dune::Functions } // namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTNODETORANGEMAP_HH dune-functions-2.5.1/dune/functions/functionspacebases/flatmultiindex.hh000066400000000000000000000030311313314422100266430ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_FLATMULTIINDEX_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_FLATMULTIINDEX_HH #include #include namespace Dune { namespace Functions { /** * \brief A multi index class with only one level * * This only adds a cast to size_type to std::array. * Hence MultiIndices of type FlatMultiIndex can be used like * classic indices. */ template class FlatMultiIndex : public std::array { public: constexpr FlatMultiIndex() = default; /** * \brief Construct from initializer_list * * This is needed because std::array does not have * a constructor from initializer list. Instead * the list initialization of an std::array is * an aggregate initialization and hence not * visible in the derived class. */ FlatMultiIndex(std::initializer_list const &l) : std::array{{*l.begin()}} {} operator const size_type& () const { return this->operator[](0); } operator size_type& () { return this->operator[](0); } inline friend std::size_t hash_value(const FlatMultiIndex& arg) { return std::hash()(arg); } }; } // end namespace Functions } // end namespace Dune DUNE_DEFINE_HASH(DUNE_HASH_TEMPLATE_ARGS(typename size_type),DUNE_HASH_TYPE(Dune::Functions::FlatMultiIndex)) #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_FLATMULTIINDEX_HH dune-functions-2.5.1/dune/functions/functionspacebases/flatvectorbackend.hh000066400000000000000000000031651313314422100273030ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_FLATVECTORBACKEND_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_FLATVECTORBACKEND_HH #include #include namespace Dune { namespace Functions { template struct FlatVectorBackend { template(), int>::type = 0> static auto getEntry(VV&& v, const Index& i) ->decltype(v[i]) { return v[i]; } template(), int>::type = 0> static auto getEntry(VV&& v, const Index& i) ->decltype(v) { return std::forward(v); } template(), int>::type = 0> static auto size(VV&& v) ->decltype(v.size()) { return v.size(); } template(), int>::type = 0> static std::size_t size(VV&& v) { return 1; } }; template struct FlatVectorBackend > { template static auto getEntry(VV&& v, const Index& i) -> decltype(v[i/m][i%m]) { return v[i/m][i%m]; } template static int size(VV&& v) { return n*m; } }; } // namespace Dune::Functions } // namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_FLATVECTORBACKEND_HH dune-functions-2.5.1/dune/functions/functionspacebases/hierarchicvectorwrapper.hh000066400000000000000000000155541313314422100305540ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_HIERARCHICVECTORWRAPPER_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_HIERARCHICVECTORWRAPPER_HH #include #include #include #include #include #include #include namespace Dune { namespace Functions { namespace Imp { // Construct default coefficent type from vector and multiindex type // This requires that MultiIndex has a static size. Otherwise the // vector type itself is returned. template struct CoefficientType { template struct DefaultCoefficientTypeHelper { using E0 = decltype(std::declval()[Dune::TypeTree::Indices::_0]); using type = typename DefaultCoefficientTypeHelper::type; }; template struct DefaultCoefficientTypeHelper { using type = E; }; template::value, int>::type = 0> static constexpr std::size_t getStaticSizeOrZero() { return StaticSize::value; } template::value, int>::type = 0> static constexpr std::size_t getStaticSizeOrZero() { return 0; } using type = typename DefaultCoefficientTypeHelper()>::type; }; } // namespace Imp /** * \brief A wrapper providing multiindex access to vector entries * * The coefficient type should be a type such that the coefficients * entries for each global basis function can be cast to this type. * This is necessary because the wrapper cannot determine this type * automatically for multi-type containers and non-uniform indices. * The reason for this is, that the multi-index type will then be * dynamically sized such that the index depth cannot statically * be determined from the multi-indices. However, the compiler needs * a fixed termination criterion for instantiation of recursive * functions. * * If no coefficient type is given, the wrapper tries to determine * the coefficient type on its own assuming that the multi-indices * have fixed size. * * \tparam V Type of the raw wrapper vector * \tparam CO Coefficient type */ template class HierarchicVectorWrapper { template using Coefficient = typename std::conditional< std::is_same::value and HasStaticSize::value, typename Imp::CoefficientType::type, CO >::type; using size_type = std::size_t; template(), int>::type = 0, typename std::enable_if< not models(), int>::type = 0> static void resizeHelper(C& c, const SizeProvider& sizeProvider, typename SizeProvider::SizePrefix prefix) { auto size = sizeProvider.size(prefix); if (size != 0) DUNE_THROW(RangeError, "Can't resize scalar vector entry v[" << prefix << "] to size(" << prefix << ")=" << size); } struct StaticResizeHelper { template static void apply(I&& i, C& c, const SizeProvider& sizeProvider, typename SizeProvider::SizePrefix prefix) { prefix.back() = i; resizeHelper(c[i], sizeProvider, prefix); } }; template(), int>::type = 0, typename std::enable_if< models(), int>::type = 0> static void resizeHelper(C& c, const SizeProvider& sizeProvider, typename SizeProvider::SizePrefix prefix) { auto size = sizeProvider.size(prefix); if (size == 0) return; if (c.size() != size) DUNE_THROW(RangeError, "Can't resize statically sized vector entry v[" << prefix << "] of size " << c.size() << " to size(" << prefix << ")=" << size); using namespace Dune::Hybrid; prefix.push_back(0); forEach(integralRange(Hybrid::size(c)), [&](auto&& i) { StaticResizeHelper::apply(i, c, sizeProvider, prefix); }); } template(), int>::type = 0> static void resizeHelper(C& c, const SizeProvider& sizeProvider, typename SizeProvider::SizePrefix prefix) { auto size = sizeProvider.size(prefix); if (size==0) { if (c.size()==0) DUNE_THROW(RangeError, "Can't resize dynamically sized vector entry v[" << prefix << "]. Its size is 0 but the target size is unknown due to size(" << prefix << ")=0."); else return; } c.resize(size); prefix.push_back(0); for(std::size_t i=0; i using Entry = Coefficient; HierarchicVectorWrapper(Vector& vector) : vector_(&vector) {} template void resize(const SizeProvider& sizeProvider) { typename SizeProvider::SizePrefix prefix; prefix.resize(0); resizeHelper(*vector_, sizeProvider, prefix); } template const Entry& operator[](const MultiIndex& index) const { return hybridMultiIndexAccess&>(*vector_, index); } template Entry& operator[](const MultiIndex& index) { return hybridMultiIndexAccess&>(*vector_, index); } template const Entry& operator()(const MultiIndex& index) const { return (*this)[index]; } template Entry& operator()(const MultiIndex& index) { return (*this)[index]; } const Vector& vector() const { return *vector_; } Vector& vector() { return *vector_; } private: Vector* vector_; }; template HierarchicVectorWrapper< V > hierarchicVector(V& v) { return HierarchicVectorWrapper(v); } template(), int>::type = 0> V& makeHierarchicVectorForMultiIndex(V& v) { return v; } template(), int>::type = 0> HierarchicVectorWrapper< V > makeHierarchicVectorForMultiIndex(V& v) { return HierarchicVectorWrapper(v); } } // namespace Dune::Functions } // namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_HIERARCHICVECTORWRAPPER_HH dune-functions-2.5.1/dune/functions/functionspacebases/interpolate.hh000066400000000000000000000307511313314422100261510ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_INTERPOLATE_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_INTERPOLATE_HH #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Dune { namespace Functions { namespace Imp { struct AllTrueBitSetVector { struct AllTrueBitSet { bool test(int i) const { return true; } } allTrue_; operator bool() const { return true; } template const AllTrueBitSetVector& operator[](const I&) const { return *this; } template void resize(const SP&) const {} }; template class LocalInterpolateVisitor : public TypeTree::TreeVisitor , public TypeTree::DynamicTraversal { public: using Basis = B; using LocalIndexSet = typename B::LocalIndexSet; using MultiIndex = typename LocalIndexSet::MultiIndex; using LocalFunction = LF; using Tree = T; using HierarchicVector = HV; using HierarchicBitVector = HBV; using NodeToRangeEntry = NTRE; using GridView = typename Basis::GridView; using Element = typename GridView::template Codim<0>::Entity; using LocalDomain = typename Element::Geometry::LocalCoordinate; using GlobalDomain = typename Element::Geometry::GlobalCoordinate; using CoefficientBlock = typename std::decay()[std::declval()])>::type; using BitVectorBlock = typename std::decay()[std::declval()])>::type; LocalInterpolateVisitor(const B& basis, HV& coeff, const HBV& bitVector, const LF& localF, const LocalIndexSet& localIndexSet, const NodeToRangeEntry& nodeToRangeEntry) : vector_(coeff), localF_(localF), bitVector_(bitVector), localIndexSet_(localIndexSet), nodeToRangeEntry_(nodeToRangeEntry) { static_assert(Dune::Functions::Concept::isCallable(), "Function passed to LocalInterpolateVisitor does not model the Callable concept"); } template void pre(Node& node, TreePath treePath) {} template void post(Node& node, TreePath treePath) {} template void leaf(Node& node, TreePath treePath) { using FiniteElement = typename Node::FiniteElement; using FiniteElementRange = typename FiniteElement::Traits::LocalBasisType::Traits::RangeType; using FunctionBaseClass = typename Dune::LocalFiniteElementFunctionBase::type; // Note that we capture j by reference. Hence we can switch // the selected component later on by modifying j. Maybe we // should avoid this naughty statefull lambda hack in favor // of a separate helper class. std::size_t j=0; auto localFj = [&](const LocalDomain& x){ const auto& y = localF_(x); const auto& y_node = nodeToRangeEntry_(node, y); using FunctionRange = typename std::decay::type; return FlatVectorBackend::getEntry(y_node, j); }; using FunctionFromCallable = typename Dune::Functions::FunctionFromCallable; auto interpolationValues = std::vector(); auto&& fe = node.finiteElement(); // We loop over j defined above and thus over the components of the // range type of localF_. auto blockSize = FlatVectorBackend::size(vector_[localIndexSet_.index(0)]); for(j=0; j::getEntry(bitVectorBlock,j); if (interpolateHere) { auto&& vectorBlock = vector_[multiIndex]; FlatVectorBackend::getEntry(vectorBlock, j) = interpolationValues[i]; } } } } protected: HierarchicVector& vector_; const LocalFunction& localF_; const HierarchicBitVector& bitVector_; const LocalIndexSet& localIndexSet_; const NodeToRangeEntry& nodeToRangeEntry_; }; } // namespace Imp /** * \brief Interpolate given function in discrete function space * * Interpolation is done wrt the leaf node of the ansatz tree * corresponding to the given tree path. * * Notice that this will only work if the range type of f and * the block type of coeff are compatible and supported by * FlatVectorBackend. * * \param basis Global function space basis of discrete function space * \param treePath Tree path specifying the part of the ansatz tree to use * \param coeff Coefficient vector to represent the interpolation * \param f Function to interpolate * \param nodeToRangeEntry Polymorphic functor mapping local ansatz nodes to range-indices of given function * \param bitVector A vector with flags marking all DOFs that should be interpolated */ template void interpolateTreeSubset(const B& basis, const TypeTree::HybridTreePath& treePath, C&& coeff, const F& f, const NTRE& nodeToRangeEntry, const BV& bv) { using GridView = typename B::GridView; using Element = typename GridView::template Codim<0>::Entity; using Tree = typename std::decay::type; using GlobalDomain = typename Element::Geometry::GlobalCoordinate; static_assert(Dune::Functions::Concept::isCallable(), "Function passed to interpolate does not model the Callable concept"); auto&& gridView = basis.gridView(); auto&& bitVector = makeHierarchicVectorForMultiIndex(bv); auto&& vector = makeHierarchicVectorForMultiIndex(coeff); vector.resize(sizeInfo(basis)); // Make a grid function supporting local evaluation out of f auto gf = makeGridViewFunction(f, gridView); // Obtain a local view of f auto localF = localFunction(gf); auto localView = basis.localView(); auto localIndexSet = basis.localIndexSet(); for (const auto& e : elements(gridView)) { localView.bind(e); localIndexSet.bind(localView); localF.bind(e); auto&& subTree = TypeTree::child(localView.tree(),treePath); Imp::LocalInterpolateVisitor localInterpolateVisitor(basis, vector, bitVector, localF, localIndexSet, nodeToRangeEntry); TypeTree::applyToTree(subTree,localInterpolateVisitor); } } template void interpolateTreeSubset(const B& basis, const TypeTree::HybridTreePath& treePath, C&& coeff, const F& f, const BV& bitVector) { interpolateTreeSubset(basis, treePath, coeff, f, makeDefaultNodeToRangeMap(basis, treePath), bitVector); } template void interpolateTree(const B& basis, const TypeTree::HybridTreePath& treePath, C&& coeff, const F& f, const NTRE& nodeToRangeEntry) { interpolateTreeSubset(basis, treePath, coeff, f, nodeToRangeEntry, Imp::AllTrueBitSetVector()); } template void interpolateTree(const B& basis, const TypeTree::HybridTreePath& treePath, C&& coeff, const F& f) { interpolateTreeSubset(basis, treePath, coeff, f, makeDefaultNodeToRangeMap(basis, treePath), Imp::AllTrueBitSetVector()); } /** * \brief Interpolate given function in discrete function space * * Interpolation is done wrt the leaf node of the ansatz tree * corresponding to the given tree path. * * Notice that this will only work if the range type of f and * the block type of coeff are compatible and supported by * FlatVectorBackend. * * \param basis Global function space basis of discrete function space * \param treePath Tree path specifying the part of the ansatz tree to use * \param coeff Coefficient vector to represent the interpolation * \param f Function to interpolate * \param bitVector A vector with flags marking all DOFs that should be interpolated */ template void interpolate(const B& basis, const TypeTree::HybridTreePath& treePath, C&& coeff, const F& f, const BV& bitVector) { interpolateTreeSubset(basis, treePath, coeff, f, makeDefaultNodeToRangeMap(basis, treePath), bitVector); } namespace Imp { template constexpr std::true_type isHybridTreePath(const TypeTree::HybridTreePath&) { return {}; } template constexpr std::false_type isHybridTreePath(const T&) { return {}; } template constexpr auto isHybridTreePath() -> decltype(isHybridTreePath(std::declval>())) { return {}; } } /** * \brief Interpolate given function in discrete function space * * Interpolation is done wrt the leaf node of the ansatz tree * corresponding to the given tree path. Only vector coefficients marked as 'true' in the * bitVector argument are interpolated. Use this, e.g., to interpolate Dirichlet boundary values. * * Notice that this will only work if the range type of f and * the block type of coeff are compatible and supported by * FlatVectorBackend. * * \param basis Global function space basis of discrete function space * \param coeff Coefficient vector to represent the interpolation * \param f Function to interpolate * \param bitVector A vector with flags marking all DOFs that should be interpolated */ template (), int> = 0> void interpolate(const B& basis, C&& coeff, const F& f, const BV& bitVector) { auto root = Dune::TypeTree::hybridTreePath(); interpolateTreeSubset(basis, root, coeff, f, makeDefaultNodeToRangeMap(basis, root), bitVector); } /** * \brief Interpolate given function in discrete function space * * Notice that this will only work if the range type of f and * the block type of coeff are compatible and supported by * FlatVectorBackend. * * This function will only work, if the local ansatz tree of * the basis is trivial, i.e., a single leaf node. * * \param basis Global function space basis of discrete function space * \param coeff Coefficient vector to represent the interpolation * \param f Function to interpolate */ template void interpolate(const B& basis, C&& coeff, const F& f) { interpolate (basis, Dune::TypeTree::hybridTreePath(), coeff, f, Imp::AllTrueBitSetVector()); } /** * \brief Interpolate given function in discrete function space * * Interpolation is done wrt the leaf node of the ansatz tree * corresponding to the given tree path. * * Notice that this will only work if the range type of f and * the block type of corresponding coeff entries are compatible * and supported by FlatVectorBackend. * * \param basis Global function space basis of discrete function space * \param treePath Tree path specifying the part of the ansatz tree to use * \param coeff Coefficient vector to represent the interpolation * \param f Function to interpolate */ template void interpolate(const B& basis, const TypeTree::HybridTreePath& treePath, C&& coeff, const F& f) { interpolate (basis, treePath, coeff, f, Imp::AllTrueBitSetVector()); } } // namespace Functions } // namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_INTERPOLATE_HH dune-functions-2.5.1/dune/functions/functionspacebases/lagrangebasis.hh000066400000000000000000000026531313314422100264250ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEBASIS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEBASIS_HH #include #include #include namespace Dune { namespace Functions { namespace BasisBuilder { template Imp::PQkNodeFactoryBuilder lagrange() { return{}; } } // end namespace BasisBuilder /** \brief Nodal basis of a scalar k-th-order Lagrangean finite element space * * \ingroup FunctionSpaceBasesImplementations * * \note This only works for certain grids. The following restrictions hold * - If k is no larger than 2, then the grids can have any dimension * - If k is larger than 3 then the grid must be two-dimensional * - If k is 3, then the grid can be 3d *if* it is a simplex grid * * All arguments passed to the constructor will be forwarded to the constructor * of PQkNodeFactory. * * \tparam GV The GridView that the space is defined on * \tparam k The order of the basis */ template using LagrangeBasis = DefaultGlobalBasis> >; } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_PQKNODALBASIS_HH dune-functions-2.5.1/dune/functions/functionspacebases/lagrangedgbasis.hh000066400000000000000000000210521313314422100267320ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEDGBASIS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEDGBASIS_HH #include #include #include #include #include #include namespace Dune { namespace Functions { // ***************************************************************************** // This is the reusable part of the basis. It contains // // LagrangeDGNodeFactory // LagrangeDGNodeIndexSet // LagrangeDGNode // // The factory allows to create the others and is the owner of possible shared // state. These three components do _not_ depend on the global basis or index // set and can be used without a global basis. // ***************************************************************************** template using LagrangeDGNode = PQkNode; template class LagrangeDGNodeIndexSet; template class LagrangeDGNodeFactory { static const int dim = GV::dimension; public: /** \brief The grid view that the FE space is defined on */ using GridView = GV; using size_type = std::size_t; // Precompute the number of dofs per entity type const static int dofsPerEdge = k+1; const static int dofsPerTriangle = (k+1)*(k+2)/2; const static int dofsPerQuad = (k+1)*(k+1); const static int dofsPerTetrahedron = (k+1)*(k+2)*(k+3)/6; const static int dofsPerPrism = (k+1)*(k+1)*(k+2)/2; const static int dofsPerHexahedron = (k+1)*(k+1)*(k+1); const static int dofsPerPyramid = (k+1)*(k+2)*(2*k+3)/6; template using Node = LagrangeDGNode; template using IndexSet = LagrangeDGNodeIndexSet; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = MI; using SizePrefix = Dune::ReservedVector; /** \brief Constructor for a given grid view object */ LagrangeDGNodeFactory(const GridView& gv) : gridView_(gv) {} void initializeIndices() { switch (dim) { case 1: { break; } case 2: { GeometryType triangle; triangle.makeTriangle(); quadrilateralOffset_ = dofsPerTriangle * gridView_.size(triangle); break; } case 3: { GeometryType tetrahedron; tetrahedron.makeSimplex(3); prismOffset_ = dofsPerTetrahedron * gridView_.size(tetrahedron); GeometryType prism; prism.makePrism(); hexahedronOffset_ = prismOffset_ + dofsPerPrism * gridView_.size(prism); GeometryType hexahedron; hexahedron.makeCube(3); pyramidOffset_ = hexahedronOffset_ + dofsPerHexahedron * gridView_.size(hexahedron); break; } } } /** \brief Obtain the grid view that the basis is defined on */ const GridView& gridView() const { return gridView_; } void update(const GridView& gv) { gridView_ = gv; } template Node node(const TP& tp) const { return Node{tp}; } template IndexSet indexSet() const { return IndexSet{*this}; } size_type size() const { switch (dim) { case 1: return dofsPerEdge*gridView_.size(0); case 2: { GeometryType triangle, quad; triangle.makeTriangle(); quad.makeQuadrilateral(); return dofsPerTriangle*gridView_.size(triangle) + dofsPerQuad*gridView_.size(quad); } case 3: { GeometryType tetrahedron, pyramid, prism, hexahedron; tetrahedron.makeTetrahedron(); pyramid.makePyramid(); prism.makePrism(); hexahedron.makeCube(3); return dofsPerTetrahedron*gridView_.size(tetrahedron) + dofsPerPyramid*gridView_.size(pyramid) + dofsPerPrism*gridView_.size(prism) + dofsPerHexahedron*gridView_.size(hexahedron); } } DUNE_THROW(Dune::NotImplemented, "No size method for " << dim << "d grids available yet!"); } //! Return number possible values for next position in multi index size_type size(const SizePrefix prefix) const { if (prefix.size() == 0) return size(); assert(false); } /** \todo This method has been added to the interface without prior discussion. */ size_type dimension() const { return size(); } size_type maxNodeSize() const { return StaticPower<(k+1),GV::dimension>::power; } //protected: GridView gridView_; size_t quadrilateralOffset_; size_t pyramidOffset_; size_t prismOffset_; size_t hexahedronOffset_; }; template class LagrangeDGNodeIndexSet { // Cannot be an enum -- otherwise the switch statement below produces compiler warnings static const int dim = GV::dimension; public: using size_type = std::size_t; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = MI; using NodeFactory = LagrangeDGNodeFactory; using Node = typename NodeFactory::template Node; LagrangeDGNodeIndexSet(const NodeFactory& nodeFactory) : nodeFactory_(&nodeFactory) {} /** \brief Bind the view to a grid element * * Having to bind the view to an element before being able to actually access any of its data members * offers to centralize some expensive setup code in the 'bind' method, which can save a lot of run-time. */ void bind(const Node& node) { node_ = &node; } /** \brief Unbind the view */ void unbind() { node_ = nullptr; } /** \brief Size of subtree rooted in this node (element-local) */ size_type size() const { return node_->finiteElement().size(); } //! Maps from subtree index set [0..size-1] to a globally unique multi index in global basis MultiIndex index(size_type i) const { const auto& gridIndexSet = nodeFactory_->gridView().indexSet(); const auto& element = node_->element(); switch (dim) { case 1: { return {nodeFactory_->dofsPerEdge*gridIndexSet.subIndex(element,0,0) + i}; } case 2: { if (element.type().isTriangle()) { return {nodeFactory_->dofsPerTriangle*gridIndexSet.subIndex(element,0,0) + i}; } else if (element.type().isQuadrilateral()) { return { nodeFactory_->quadrilateralOffset_ + nodeFactory_->dofsPerQuad*gridIndexSet.subIndex(element,0,0) + i}; } else DUNE_THROW(Dune::NotImplemented, "2d elements have to be triangles or quadrilaterals"); } case 3: { if (element.type().isTetrahedron()) { return {nodeFactory_->dofsPerTetrahedron*gridIndexSet.subIndex(element,0,0) + i}; } else if (element.type().isPrism()) { return { nodeFactory_->prismOffset_ + nodeFactory_->dofsPerPrism*gridIndexSet.subIndex(element,0,0) + i}; } else if (element.type().isHexahedron()) { return { nodeFactory_->hexahedronOffset_ + nodeFactory_->dofsPerHexahedron*gridIndexSet.subIndex(element,0,0) + i}; } else if (element.type().isPyramid()) { return { nodeFactory_->pyramidOffset_ + nodeFactory_->dofsPerPyramid*gridIndexSet.subIndex(element,0,0) + i}; } else DUNE_THROW(Dune::NotImplemented, "3d elements have to be tetrahedrons, prisms, hexahedrons or pyramids"); } } DUNE_THROW(Dune::NotImplemented, "No index method for " << dim << "d grids available yet!"); } protected: const NodeFactory* nodeFactory_; const Node* node_; }; // ***************************************************************************** // This is the actual global basis implementation based on the reusable parts. // ***************************************************************************** /** \brief Basis of a scalar k-th-order Lagrangean-DG finite element space * * \ingroup FunctionSpaceBasesImplementations * * \tparam GV The GridView that the space is defined on * \tparam k The order of the basis */ template using LagrangeDGBasis = DefaultGlobalBasis> >; } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEDGBASIS_HH dune-functions-2.5.1/dune/functions/functionspacebases/nodes.hh000066400000000000000000000137521313314422100247350ustar00rootroot00000000000000#ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_NODES_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_NODES_HH #include #include #include #include #include namespace Dune { namespace Functions { namespace { template struct ClearSizeVisitor : public TypeTree::TreeVisitor , public TypeTree::DynamicTraversal { template void pre(Node& node, TreePath treePath) { leaf(node,treePath); node.setSize(0); } template void leaf(Node& node, TreePath treePath) { node.setOffset(offset_); } ClearSizeVisitor(size_type offset) : offset_(offset) {} const size_type offset_; }; template struct BindVisitor : public TypeTree::TreeVisitor , public TypeTree::DynamicTraversal { template void pre(Node& node, TreePath treePath) { node.setOffset(offset_); } template void post(Node& node, TreePath treePath) { node.setSize(offset_ - node.offset()); } template void leaf(Node& node, TreePath treePath) { node.setOffset(offset_); node.bind(entity_); offset_ += node.size(); } BindVisitor(const Entity& entity, size_type offset = 0) : entity_(entity) , offset_(offset) {} const Entity& entity_; size_type offset_; }; template struct InitializeTreeVisitor : public TypeTree::TreeVisitor, public TypeTree::DynamicTraversal { template void pre(Node& node, TreePath treePath) { node.setTreeIndex(treeIndex_); ++treeIndex_; } template void leaf(Node& node, TreePath treePath) { node.setTreeIndex(treeIndex_); ++treeIndex_; } InitializeTreeVisitor(size_type treeIndexOffset = 0) : treeIndex_(treeIndexOffset) {} size_type treeIndex_; }; } template class BasisNodeMixin { template friend struct ClearSizeVisitor; template friend struct BindVisitor; template friend struct InitializeTreeVisitor; public: using TreePath = TP; using size_type = std::size_t; BasisNodeMixin(const TreePath& treePath) : offset_(0), size_(0), treePath_(treePath), treeIndex_(0) {} size_type localIndex(size_type i) const { return offset_ + i; } size_type size() const { return size_; } const TreePath& treePath() const { return treePath_; } size_type treeIndex() const { return treeIndex_; } size_type offset() const { return offset_; } protected: void setOffset(const size_type offset) { offset_ = offset; } void setSize(const size_type size) { size_ = size; } void setTreeIndex(size_type treeIndex) { treeIndex_ = treeIndex; } private: size_type offset_; size_type size_; const TreePath treePath_; size_type treeIndex_; }; template class LeafBasisNode : public BasisNodeMixin, public TypeTree::LeafNode { using Mixin = BasisNodeMixin; public: using TreePath = TP; using size_type = std::size_t; LeafBasisNode(TreePath treePath = TreePath()) : Mixin(treePath) {} }; template class PowerBasisNode : public BasisNodeMixin, public TypeTree::PowerNode { using Mixin = BasisNodeMixin; using Node = TypeTree::PowerNode; public: PowerBasisNode(const TP& tp) : Mixin(tp) {} PowerBasisNode(const TP& tp, const typename Node::NodeStorage& children) : Mixin(tp), Node(children) {} }; template class CompositeBasisNode : public BasisNodeMixin, public TypeTree::CompositeNode { using Mixin = BasisNodeMixin; using Node = TypeTree::CompositeNode; public: CompositeBasisNode(const TP& tp) : Mixin(tp) {} CompositeBasisNode(const TP& tp, const typename Node::NodeStorage& children) : Mixin(tp), Node(children) {} template CompositeBasisNode(const shared_ptr&... children, const TP& tp) : Mixin(tp) , Node(children...) {} }; template void clearSize(Tree& tree, std::size_t offset) { TypeTree::applyToTree(tree,ClearSizeVisitor(offset)); } template void bindTree(Tree& tree, const Entity& entity, std::size_t offset = 0) { BindVisitor visitor(entity,offset); TypeTree::applyToTree(tree,visitor); } template void initializeTree(Tree& tree, std::size_t treeIndexOffset = 0) { InitializeTreeVisitor visitor(treeIndexOffset); TypeTree::applyToTree(tree,visitor); } } // namespace Functions } // namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_NODES_HH dune-functions-2.5.1/dune/functions/functionspacebases/powerbasis.hh000066400000000000000000000320001313314422100257660ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_POWERBASIS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_POWERBASIS_HH #include #include #include #include #include #include #include #include namespace Dune { namespace Functions { // ***************************************************************************** // This is the reusable part of the power bases. It contains // // PowerNodeFactory // PowerNodeIndexSet // // The factory allows to create the others and is the owner of possible shared // state. These components do _not_ depend on the global basis or index // set and can be used without a global basis. // ***************************************************************************** template class PowerNodeIndexSet; /** * \brief A factory for power bases * * This node factory represente a power of a given node factory. * Its node type is a PowerBasisNodes for the given subnode. * * \tparam MI Type to be used for multi-indices * \tparam IMS An IndexMergingStrategy used to merge the global indices of the child factories * \tparam SF The child factory * \tparam C The exponent of the power node */ template class PowerNodeFactory { static const std::size_t children = C; template friend class PowerNodeIndexSet; public: //! The child factory using SubFactory = SF; //! The grid view that the FE basis is defined on using GridView = typename SF::GridView; //! Type used for indices and size information using size_type = std::size_t; //! Strategy used to merge the global indices of the child factories using IndexMergingStrategy = IMS; template using SubNode = typename SubFactory::template Node; template using SubIndexSet = typename SubFactory::template IndexSet; //! Template mapping root tree path to type of created tree node template using Node = PowerBasisNode, children>; //! Template mapping root tree path to type of created tree node index set template using IndexSet = PowerNodeIndexSet; //! Type used for global numbering of the basis vectors using MultiIndex = MI; //! Type used for prefixes handed to the size() method using SizePrefix = Dune::ReservedVector; private: using SubMultiIndex = MI; public: /** * \brief Constructor for given child factory objects * * The child factories will be stored as copies */ template = 0, enableIfConstructible = 0> PowerNodeFactory(SFArgs&&... sfArgs) : subFactory_(std::forward(sfArgs)...) {} //! Initialize the global indices void initializeIndices() { subFactory_.initializeIndices(); } //! Obtain the grid view that the basis is defined on const GridView& gridView() const { return subFactory_.gridView(); } //! Update the stored grid view, to be called if the grid has changed void update(const GridView& gv) { subFactory_.update(gv); } /** * \brief Create tree node with given root tree path * * \tparam TP Type of root tree path * \param tp Root tree path * * By passing a non-trivial root tree path this can be used * to create a node suitable for being placed in a tree at * the position specified by the root tree path. */ template Node node(const TP& tp) const { auto node = Node(tp); for (std::size_t i=0; i IndexSet indexSet() const { return IndexSet{*this}; } //! Same as size(prefix) with empty prefix size_type size() const { return size({}); } //! Return number of possible values for next position in multi index size_type size(const SizePrefix& prefix) const { return size(prefix, IndexMergingStrategy{}); } private: size_type size(const SizePrefix& prefix, BasisBuilder::FlatInterleaved) const { // The root index size is the root index size of a single subnode // multiplied by the number of subnodes because we enumerate all // child indices in a row. if (prefix.size() == 0) return children*subFactory_.size({}); // The first prefix entry refers to one of the (root index size) // subindex trees. Hence we have to first compute the corresponding // prefix entry for a single subnode subnode. The we can append // the other prefix entries unmodified, because the index tree // looks the same after the first level. typename SubFactory::SizePrefix subPrefix; subPrefix.push_back(prefix[0] / children); for(std::size_t i=1; i class PowerNodeIndexSet { static const std::size_t children = C; public: using SubFactory = SF; /** \brief The grid view that the FE space is defined on */ using GridView = typename SF::GridView; using size_type = std::size_t; using IndexMergingStrategy = IMS; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = MI; using NodeFactory = PowerNodeFactory; using Node = typename NodeFactory::template Node; using SubTreePath = typename TypeTree::Child::TreePath; using SubNodeIndexSet = typename NodeFactory::SubFactory::template IndexSet; PowerNodeIndexSet(const NodeFactory & nodeFactory) : nodeFactory_(&nodeFactory), subNodeIndexSet_(nodeFactory_->subFactory_.template indexSet()) {} void bind(const Node& node) { using namespace TypeTree::Indices; node_ = &node; subNodeIndexSet_.bind(node.child(_0)); } void unbind() { node_ = nullptr; subNodeIndexSet_.unbind(); } size_type size() const { return node_->size(); } MultiIndex index(const size_type& localIndex) const { return index(localIndex, IndexMergingStrategy{}); } MultiIndex index(const size_type& localIndex, BasisBuilder::FlatInterleaved) const { using namespace Dune::TypeTree::Indices; size_type subTreeSize = node_->child(_0).size(); size_type subLocalIndex = localIndex % subTreeSize; size_type component = localIndex / subTreeSize; MultiIndex mi = subNodeIndexSet_.index(subLocalIndex); mi[0] = mi[0]*children+component; return mi; } MultiIndex index(const size_type& localIndex, BasisBuilder::FlatLexicographic) const { using namespace Dune::TypeTree::Indices; size_type subTreeSize = node_->child(_0).size(); size_type subLocalIndex = localIndex % subTreeSize; size_type component = localIndex / subTreeSize; size_type firstLevelSize = nodeFactory_->subFactory_.size({}); MultiIndex mi = subNodeIndexSet_.index(subLocalIndex); mi[0] += component*firstLevelSize; return mi; } MultiIndex index(const size_type& localIndex, BasisBuilder::BlockedLexicographic) const { using namespace Dune::TypeTree::Indices; size_type subTreeSize = node_->child(_0).size(); size_type subLocalIndex = localIndex % subTreeSize; size_type component = localIndex / subTreeSize; auto subTreeMi = subNodeIndexSet_.index(subLocalIndex); MultiIndex mi; mi.push_back(component); for(std::size_t i=0; ichild(_0).size(); size_type subLocalIndex = localIndex % subTreeSize; size_type component = localIndex / subTreeSize; auto subTreeMi = subNodeIndexSet_.index(subLocalIndex); MultiIndex mi; for(std::size_t i=0; i struct PowerNodeFactoryBuilder { static const bool isBlocked = std::is_same::value or std::is_same::value; static const std::size_t requiredMultiIndexSize=SubFactoryTag::requiredMultiIndexSize + (std::size_t)(isBlocked); template auto build(const GridView& gridView) -> PowerNodeFactory(std::declval())), k> { return {SubFactoryTag().template build(gridView)}; } }; } // end namespace BasisBuilder::Imp /** * \brief Create a factory builder that can build a PowerNodeFactory * * \ingroup FunctionSpaceBasesImplementations * * \tparam SubFactoryTag Types of child factory builder and IndexMergingStrategy type * \tparam IndexMergingStrategy An IndexMergingStrategy type * \param tag Child factory builder objects and an IndexMergingStrategy * \param ims IndexMergingStrategy to be used * * This overload can be used to explicitly supply an IndexMergingStrategy. */ template Imp::PowerNodeFactoryBuilder power(SubFactoryTag&& tag, const IndexMergingStrategy& ims) { return{}; } /** * \brief Create a factory builder that can build a PowerNodeFactory * * \ingroup FunctionSpaceBasesImplementations * * \tparam SubFactoryTag Types of child factory builder and IndexMergingStrategy type * \param tag Child factory builder objects and an IndexMergingStrategy * * This overload will select the BasisBuilder::BlockedLexicographic strategy. */ template Imp::PowerNodeFactoryBuilder power(SubFactoryTag&& tag) { return{}; } } // end namespace BasisBuilder } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_POWERBASIS_HH dune-functions-2.5.1/dune/functions/functionspacebases/pq1nodalbasis.hh000066400000000000000000000167011313314422100263630ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_PQ1NODALBASIS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_PQ1NODALBASIS_HH #include #include #include #include #include #include #include namespace Dune { namespace Functions { // ***************************************************************************** // This is the reusable part of the basis. It contains // // PQ1NodeFactory // PQ1NodeIndexSet // PQ1Node // // The factory allows to create the others and is the owner of possible shared // state. These three components do _not_ depend on the global basis or index // set and can be used without a global basis. // ***************************************************************************** template class PQ1Node; template class PQ1NodeIndexSet; template class PQ1NodeFactory; /** * \brief Factory for a first order PQ-lagrange basis * * \ingroup FunctionSpaceBasesImplementations * * \tparam GV The grid view that the FE basis is defined on * \tparam MI Type to be used for multi-indices * * \note This mainly serves as an example, since PQkNodeFactory * provides the same functionality. */ template class PQ1NodeFactory { static const int dim = GV::dimension; public: //! The grid view that the FE basis is defined on using GridView = GV; //! Type used for indices and size information using size_type = std::size_t; //! Template mapping root tree path to type of created tree node template using Node = PQ1Node; //! Template mapping root tree path to type of created tree node index set template using IndexSet = PQ1NodeIndexSet; //! Type used for global numbering of the basis vectors using MultiIndex = MI; //! Type used for prefixes handed to the size() method using SizePrefix = Dune::ReservedVector; //! Constructor for a given grid view object PQ1NodeFactory(const GridView& gv) : gridView_(gv) {} //! Initialize the global indices void initializeIndices() {} //! Obtain the grid view that the basis is defined on const GridView& gridView() const { return gridView_; } //! Update the stored grid view, to be called if the grid has changed void update (const GridView& gv) { gridView_ = gv; } /** * \brief Create tree node with given root tree path * * \tparam TP Type of root tree path * \param tp Root tree path * * By passing a non-trivial root tree path this can be used * to create a node suitable for being placed in a tree at * the position specified by the root tree path. */ template Node node(const TP& tp) const { return Node{tp}; } /** * \brief Create tree node index set with given root tree path * * \tparam TP Type of root tree path * \param tp Root tree path * * Create an index set suitable for the tree node obtained * by node(tp). */ template IndexSet indexSet() const { return IndexSet{*this}; } //! Same as size(prefix) with empty prefix size_type size() const { return (size_type)(gridView_.size(dim)); } //! Return number of possible values for next position in multi index size_type size(const SizePrefix prefix) const { if (prefix.size() == 0) return size(); if (prefix.size() == 1) return 0; DUNE_THROW(RangeError, "Method size() can only be called for prefixes of length up to one"); } //! Get the total dimension of the space spanned by this basis size_type dimension() const { return size(); } //! Get the maximal number of DOFs associated to node for any element size_type maxNodeSize() const { return StaticPower<2,GV::dimension>::power; } protected: GridView gridView_; }; template class PQ1Node : public LeafBasisNode { static const int dim = GV::dimension; static const int maxSize = StaticPower<2,GV::dimension>::power; using Base = LeafBasisNode; using FiniteElementCache = typename Dune::PQkLocalFiniteElementCache; public: using size_type = std::size_t; using TreePath = TP; using Element = typename GV::template Codim<0>::Entity; using FiniteElement = typename FiniteElementCache::FiniteElementType; PQ1Node(const TreePath& treePath) : Base(treePath), finiteElement_(nullptr), element_(nullptr) {} //! Return current element, throw if unbound const Element& element() const { return *element_; } /** \brief Return the LocalFiniteElement for the element we are bound to * * The LocalFiniteElement implements the corresponding interfaces of the dune-localfunctions module */ const FiniteElement& finiteElement() const { return *finiteElement_; } //! Bind to element. void bind(const Element& e) { element_ = &e; finiteElement_ = &(cache_.get(element_->type())); this->setSize(finiteElement_->size()); } protected: FiniteElementCache cache_; const FiniteElement* finiteElement_; const Element* element_; }; template class PQ1NodeIndexSet { enum {dim = GV::dimension}; public: using size_type = std::size_t; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = MI; using NodeFactory = PQ1NodeFactory; using Node = typename NodeFactory::template Node; PQ1NodeIndexSet(const NodeFactory& nodeFactory) : nodeFactory_(&nodeFactory) {} /** \brief Bind the view to a grid element * * Having to bind the view to an element before being able to actually access any of its data members * offers to centralize some expensive setup code in the 'bind' method, which can save a lot of run-time. */ void bind(const Node& node) { node_ = &node; } /** \brief Unbind the view */ void unbind() { node_ = nullptr; } /** \brief Size of subtree rooted in this node (element-local) */ size_type size() const { return (size_type)(node_->finiteElement().size()); } //! Maps from subtree index set [0..size-1] to a globally unique multi index in global basis MultiIndex index(size_type i) const { Dune::LocalKey localKey = node_->finiteElement().localCoefficients().localKey(i); const auto& gridIndexSet = nodeFactory_->gridView().indexSet(); const auto& element = node_->element(); return {{ (size_type)(gridIndexSet.subIndex(element,localKey.subEntity(),dim)) }}; } protected: const NodeFactory* nodeFactory_; const Node* node_; }; /** \brief Nodal basis of a scalar first-order Lagrangian finite element space * * \ingroup FunctionSpaceBasesImplementations * * \tparam GV The GridView that the space is defined on * * \note This mainly serves as an example, since PQkNodalBasis * provides the same functionality. */ template using PQ1NodalBasis = DefaultGlobalBasis> >; } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_PQ1NODALBASIS_HH dune-functions-2.5.1/dune/functions/functionspacebases/pqknodalbasis.hh000066400000000000000000000411121313314422100264470ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_PQKNODALBASIS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_PQKNODALBASIS_HH #include #include #include #include #include #include #include namespace Dune { namespace Functions { // ***************************************************************************** // This is the reusable part of the basis. It contains // // PQkNodeFactory // PQkNodeIndexSet // PQkNode // // The factory allows to create the others and is the owner of possible shared // state. These three components do _not_ depend on the global basis or index // set and can be used without a global basis. // ***************************************************************************** template class PQkNode; template class PQkNodeIndexSet; template class PQkNodeFactory; /** * \brief A factory for PQ-lagrange bases with given order * * \ingroup FunctionSpaceBasesImplementations * * \tparam GV The grid view that the FE basis is defined on * \tparam k The polynomial order of ansatz functions * \tparam MI Type to be used for multi-indices * * \note This only works for certain grids. The following restrictions hold * - If k is no larger than 2, then the grids can have any dimension * - If k is larger than 3 then the grid must be two-dimensional * - If k is 3, then the grid can be 3d *if* it is a simplex grid */ template class PQkNodeFactory { static const int dim = GV::dimension; public: //! The grid view that the FE basis is defined on using GridView = GV; //! Type used for indices and size information using size_type = std::size_t; private: template friend class PQkNodeIndexSet; // Precompute the number of dofs per entity type const static size_type dofsPerVertex = k == 0 ? (dim == 0 ? 1 : 0) : 1; const static size_type dofsPerEdge = k == 0 ? (dim == 1 ? 1 : 0) : k-1; const static size_type dofsPerTriangle = k == 0 ? (dim == 2 ? 1 : 0) : (k-1)*(k-2)/2; const static size_type dofsPerQuad = k == 0 ? (dim == 2 ? 1 : 0) : (k-1)*(k-1); const static size_type dofsPerTetrahedron = k == 0 ? (dim == 3 ? 1 : 0) : (k-3)*(k-2)*(k-1)/6; const static size_type dofsPerPrism = k == 0 ? (dim == 3 ? 1 : 0) : (k-1)*(k-1)*(k-2)/2; const static size_type dofsPerHexahedron = k == 0 ? (dim == 3 ? 1 : 0) : (k-1)*(k-1)*(k-1); const static size_type dofsPerPyramid = k == 0 ? (dim == 3 ? 1 : 0) : (k-2)*(k-1)*(2*k-3)/6; public: //! Template mapping root tree path to type of created tree node template using Node = PQkNode; //! Template mapping root tree path to type of created tree node index set template using IndexSet = PQkNodeIndexSet; //! Type used for global numbering of the basis vectors using MultiIndex = MI; //! Type used for prefixes handed to the size() method using SizePrefix = Dune::ReservedVector; //! Constructor for a given grid view object PQkNodeFactory(const GridView& gv) : gridView_(gv) {} //! Initialize the global indices void initializeIndices() { vertexOffset_ = 0; edgeOffset_ = vertexOffset_ + dofsPerVertex * ((size_type)gridView_.size(dim)); triangleOffset_ = edgeOffset_ + dofsPerEdge * ((size_type) gridView_.size(dim-1)); GeometryType triangle; triangle.makeTriangle(); quadrilateralOffset_ = triangleOffset_ + dofsPerTriangle * ((size_type)gridView_.size(triangle)); Dune::GeometryType quadrilateral; quadrilateral.makeQuadrilateral(); if (dim==3) { tetrahedronOffset_ = quadrilateralOffset_ + dofsPerQuad * ((size_type)gridView_.size(quadrilateral)); GeometryType tetrahedron; tetrahedron.makeSimplex(3); prismOffset_ = tetrahedronOffset_ + dofsPerTetrahedron * ((size_type)gridView_.size(tetrahedron)); GeometryType prism; prism.makePrism(); hexahedronOffset_ = prismOffset_ + dofsPerPrism * ((size_type)gridView_.size(prism)); GeometryType hexahedron; hexahedron.makeCube(3); pyramidOffset_ = hexahedronOffset_ + dofsPerHexahedron * ((size_type)gridView_.size(hexahedron)); } } //! Obtain the grid view that the basis is defined on const GridView& gridView() const { return gridView_; } //! Update the stored grid view, to be called if the grid has changed void update (const GridView& gv) { gridView_ = gv; } /** * \brief Create tree node with given root tree path * * \tparam TP Type of root tree path * \param tp Root tree path * * By passing a non-trivial root tree path this can be used * to create a node suitable for being placed in a tree at * the position specified by the root tree path. */ template Node node(const TP& tp) const { return Node{tp}; } /** * \brief Create tree node index set with given root tree path * * \tparam TP Type of root tree path * \param tp Root tree path * * Create an index set suitable for the tree node obtained * by node(tp). */ template IndexSet indexSet() const { return IndexSet{*this}; } //! Same as size(prefix) with empty prefix size_type size() const { switch (dim) { case 1: return dofsPerVertex * ((size_type)gridView_.size(dim)) + dofsPerEdge*((size_type)gridView_.size(dim-1)); case 2: { GeometryType triangle, quad; triangle.makeTriangle(); quad.makeQuadrilateral(); return dofsPerVertex * ((size_type)gridView_.size(dim)) + dofsPerEdge * ((size_type)gridView_.size(dim-1)) + dofsPerTriangle * ((size_type)gridView_.size(triangle)) + dofsPerQuad * ((size_type)gridView_.size(quad)); } case 3: { GeometryType triangle, quad, tetrahedron, pyramid, prism, hexahedron; triangle.makeTriangle(); quad.makeQuadrilateral(); tetrahedron.makeTetrahedron(); pyramid.makePyramid(); prism.makePrism(); hexahedron.makeCube(3); return dofsPerVertex * ((size_type)gridView_.size(dim)) + dofsPerEdge * ((size_type)gridView_.size(dim-1)) + dofsPerTriangle * ((size_type)gridView_.size(triangle)) + dofsPerQuad * ((size_type)gridView_.size(quad)) + dofsPerTetrahedron * ((size_type)gridView_.size(tetrahedron)) + dofsPerPyramid * ((size_type)gridView_.size(pyramid)) + dofsPerPrism * ((size_type)gridView_.size(prism)) + dofsPerHexahedron * ((size_type)gridView_.size(hexahedron)); } } DUNE_THROW(Dune::NotImplemented, "No size method for " << dim << "d grids available yet!"); } //! Return number of possible values for next position in multi index size_type size(const SizePrefix prefix) const { assert(prefix.size() == 0 || prefix.size() == 1); return (prefix.size() == 0) ? size() : 0; } //! Get the total dimension of the space spanned by this basis size_type dimension() const { return size(); } //! Get the maximal number of DOFs associated to node for any element size_type maxNodeSize() const { return StaticPower<(k+1),GV::dimension>::power; } protected: GridView gridView_; size_type vertexOffset_; size_type edgeOffset_; size_type triangleOffset_; size_type quadrilateralOffset_; size_type tetrahedronOffset_; size_type pyramidOffset_; size_type prismOffset_; size_type hexahedronOffset_; }; template class PQkNode : public LeafBasisNode { static const int dim = GV::dimension; static const int maxSize = StaticPower<(k+1),GV::dimension>::power; using Base = LeafBasisNode; using FiniteElementCache = typename Dune::PQkLocalFiniteElementCache; public: using size_type = std::size_t; using TreePath = TP; using Element = typename GV::template Codim<0>::Entity; using FiniteElement = typename FiniteElementCache::FiniteElementType; PQkNode(const TreePath& treePath) : Base(treePath), finiteElement_(nullptr), element_(nullptr) {} //! Return current element, throw if unbound const Element& element() const { return *element_; } /** \brief Return the LocalFiniteElement for the element we are bound to * * The LocalFiniteElement implements the corresponding interfaces of the dune-localfunctions module */ const FiniteElement& finiteElement() const { return *finiteElement_; } //! Bind to element. void bind(const Element& e) { element_ = &e; finiteElement_ = &(cache_.get(element_->type())); this->setSize(finiteElement_->size()); } protected: FiniteElementCache cache_; const FiniteElement* finiteElement_; const Element* element_; }; template class PQkNodeIndexSet { enum {dim = GV::dimension}; public: using size_type = std::size_t; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = MI; using NodeFactory = PQkNodeFactory; using Node = typename NodeFactory::template Node; PQkNodeIndexSet(const NodeFactory& nodeFactory) : nodeFactory_(&nodeFactory), node_(nullptr) {} /** \brief Bind the view to a grid element * * Having to bind the view to an element before being able to actually access any of its data members * offers to centralize some expensive setup code in the 'bind' method, which can save a lot of run-time. */ void bind(const Node& node) { node_ = &node; } /** \brief Unbind the view */ void unbind() { node_ = nullptr; } /** \brief Size of subtree rooted in this node (element-local) */ size_type size() const { assert(node_ != nullptr); return node_->finiteElement().size(); } //! Maps from subtree index set [0..size-1] to a globally unique multi index in global basis MultiIndex index(size_type i) const { assert(node_ != nullptr); Dune::LocalKey localKey = node_->finiteElement().localCoefficients().localKey(i); const auto& gridIndexSet = nodeFactory_->gridView().indexSet(); const auto& element = node_->element(); // The dimension of the entity that the current dof is related to auto dofDim = dim - localKey.codim(); if (dofDim==0) { // vertex dof return {{ (size_type)(gridIndexSet.subIndex(element,localKey.subEntity(),dim)) }}; } if (dofDim==1) { // edge dof if (dim==1) // element dof -- any local numbering is fine return {{ nodeFactory_->edgeOffset_ + nodeFactory_->dofsPerEdge * ((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }}; else { const Dune::ReferenceElement& refElement = Dune::ReferenceElements::general(element.type()); // we have to reverse the numbering if the local triangle edge is // not aligned with the global edge auto v0 = (size_type)gridIndexSet.subIndex(element,refElement.subEntity(localKey.subEntity(),localKey.codim(),0,dim),dim); auto v1 = (size_type)gridIndexSet.subIndex(element,refElement.subEntity(localKey.subEntity(),localKey.codim(),1,dim),dim); bool flip = (v0 > v1); return {{ (flip) ? nodeFactory_->edgeOffset_ + nodeFactory_->dofsPerEdge*((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim())) + (nodeFactory_->dofsPerEdge-1)-localKey.index() : nodeFactory_->edgeOffset_ + nodeFactory_->dofsPerEdge*((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim())) + localKey.index() }}; } } if (dofDim==2) { if (dim==2) // element dof -- any local numbering is fine { if (element.type().isTriangle()) { const int interiorLagrangeNodesPerTriangle = (k-1)*(k-2)/2; return {{ nodeFactory_->triangleOffset_ + interiorLagrangeNodesPerTriangle*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }}; } else if (element.type().isQuadrilateral()) { const int interiorLagrangeNodesPerQuadrilateral = (k-1)*(k-1); return {{ nodeFactory_->quadrilateralOffset_ + interiorLagrangeNodesPerQuadrilateral*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }}; } else DUNE_THROW(Dune::NotImplemented, "2d elements have to be triangles or quadrilaterals"); } else { const Dune::ReferenceElement& refElement = Dune::ReferenceElements::general(element.type()); if (k>3) DUNE_THROW(Dune::NotImplemented, "PQkNodalBasis for 3D grids is only implemented if k<=3"); if (k==3 and !refElement.type(localKey.subEntity(), localKey.codim()).isTriangle()) DUNE_THROW(Dune::NotImplemented, "PQkNodalBasis for 3D grids with k==3 is only implemented if the grid is a simplex grid"); return {{ nodeFactory_->triangleOffset_ + ((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim())) }}; } } if (dofDim==3) { if (dim==3) // element dof -- any local numbering is fine { if (element.type().isTetrahedron()) return {{ nodeFactory_->tetrahedronOffset_ + NodeFactory::dofsPerTetrahedron*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }}; else if (element.type().isHexahedron()) return {{ nodeFactory_->hexahedronOffset_ + NodeFactory::dofsPerHexahedron*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }}; else if (element.type().isPrism()) return {{ nodeFactory_->prismOffset_ + NodeFactory::dofsPerPrism*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }}; else if (element.type().isPyramid()) return {{ nodeFactory_->pyramidOffset_ + NodeFactory::dofsPerPyramid*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }}; else DUNE_THROW(Dune::NotImplemented, "3d elements have to be tetrahedra, hexahedra, prisms, or pyramids"); } else DUNE_THROW(Dune::NotImplemented, "Grids of dimension larger than 3 are no supported"); } DUNE_THROW(Dune::NotImplemented, "Grid contains elements not supported for the PQkNodalBasis"); } protected: const NodeFactory* nodeFactory_; const Node* node_; }; namespace BasisBuilder { namespace Imp { template struct PQkNodeFactoryBuilder { static const std::size_t requiredMultiIndexSize=1; template auto build(const GridView& gridView) -> PQkNodeFactory { return {gridView}; } }; } // end namespace BasisBuilder::Imp /** * \brief Create a factory builder that can build a PQkNodeFactory * * \ingroup FunctionSpaceBasesImplementations * * \tparam k The polynomial order of ansatz functions */ template Imp::PQkNodeFactoryBuilder pq() { return{}; } } // end namespace BasisBuilder // ***************************************************************************** // This is the actual global basis implementation based on the reusable parts. // ***************************************************************************** /** \brief Nodal basis of a scalar k-th-order Lagrangean finite element space * * \ingroup FunctionSpaceBasesImplementations * * \note This only works for certain grids. The following restrictions hold * - If k is no larger than 2, then the grids can have any dimension * - If k is larger than 3 then the grid must be two-dimensional * - If k is 3, then the grid can be 3d *if* it is a simplex grid * * All arguments passed to the constructor will be forwarded to the constructor * of PQkNodeFactory. * * \tparam GV The GridView that the space is defined on * \tparam k The order of the basis */ template using PQkNodalBasis = DefaultGlobalBasis> >; } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_PQKNODALBASIS_HH dune-functions-2.5.1/dune/functions/functionspacebases/sizeinfo.hh000066400000000000000000000033251313314422100254460ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_SIZEINFO_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_SIZEINFO_HH #include namespace Dune { namespace Functions { /** * \brief A class encapsulating size information * * This class encapsulates size information of a basis. * * We may want to return this or a similar class when * calling basis.size() without arguments. Until we * decided on this, we can use sizeInfo(basis) and * use the result as size provider for the HierarchicVectorWrapper. */ template class SizeInfo { public: using Basis = B; using size_type = typename Basis::size_type; using SizePrefix = typename Basis::SizePrefix; /** * \brief Construct from basis */ SizeInfo(const Basis& basis) : basis_(&basis) {} /** * \brief Return number possible values for next position in multi index */ size_type operator()(const SizePrefix& prefix) const { return basis_->size(prefix); } /** * \brief Return number possible values for next position in multi index * * This shall vanish. It's just here such that this can be used * as size provider n place of the basis. */ size_type size(const SizePrefix& prefix) const { return basis_->size(prefix); } operator size_type () const { return basis_->dimension(); } protected: const Basis* basis_; }; template SizeInfo sizeInfo(const Basis& basis) { return SizeInfo(basis); } } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_SIZEINFO_HH dune-functions-2.5.1/dune/functions/functionspacebases/subspacebasis.hh000066400000000000000000000063511313314422100264510ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_SUBSPACEBASIS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_SUBSPACEBASIS_HH #include #include #include #include #include #include namespace Dune { namespace Functions { template class SubspaceBasis { public: using RootBasis = RB; using RootLocalView = typename RootBasis::LocalView; using PrefixPath = TP; //! The grid view that the FE space is defined on using GridView = typename RootBasis::GridView; //! Type used for global numbering of the basis vectors using MultiIndex = typename RootBasis::MultiIndex; using size_type = std::size_t; //! Type of the local view on the restriction of the basis to a single element using LocalView = SubspaceLocalView; using SizePrefix = typename RootBasis::SizePrefix; using LocalIndexSet = typename RootBasis::LocalIndexSet; /** \brief Constructor for a given grid view object */ SubspaceBasis(const RootBasis& rootBasis, const PrefixPath& prefixPath) : rootBasis_(&rootBasis), prefixPath_(prefixPath) { // static_assert(models, NodeFactory>(), "Type passed to DefaultGlobalBasis does not model the NodeFactory concept."); } /** \brief Obtain the grid view that the basis is defined on */ const GridView& gridView() const { return rootBasis_->gridView(); } /** * \todo This method has been added to the interface without prior discussion. */ size_type dimension() const { return rootBasis_->dimension(); } //! Return number of possible values for next position in empty multi index size_type size() const { return rootBasis_->size(); } //! Return number possible values for next position in multi index size_type size(const SizePrefix& prefix) const { return rootBasis_->size(prefix); } /** \brief Return local view for basis * */ LocalView localView() const { return LocalView(*this, prefixPath_); } LocalIndexSet localIndexSet() const { return rootBasis_->localIndexSet(); } const RootBasis& rootBasis() const { return *rootBasis_; } const PrefixPath& prefixPath() const { return prefixPath_; } protected: const RootBasis* rootBasis_; PrefixPath prefixPath_; }; template auto subspaceBasis(const RootBasis& rootBasis, const TypeTree::HybridTreePath& prefixPath) { using PrefixPath = TypeTree::HybridTreePath; return SubspaceBasis{rootBasis, prefixPath}; } template auto subspaceBasis(const RootBasis& rootBasis, const PrefixTreeIndices&... prefixTreeIndices) { return subspaceBasis(rootBasis, TypeTree::hybridTreePath(prefixTreeIndices...)); } } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DEFAULTGLOBALBASIS_HH dune-functions-2.5.1/dune/functions/functionspacebases/subspacelocalview.hh000066400000000000000000000067231313314422100273400ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_SUBSPACELOCALVIEW_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_SUBSPACELOCALVIEW_HH #include #include #include #include namespace Dune { namespace Functions { template class SubspaceBasis; /** \brief The restriction of a finite element basis to a single element */ template class SubspaceLocalView { using PrefixPath = PP; public: using RootLocalView = RLV; //! The global FE basis that this is a view on using GlobalBasis = SubspaceBasis; //! The grid view the global FE basis lives on using GridView = typename GlobalBasis::GridView; //! Type of the grid element we are bound to using Element = typename GridView::template Codim<0>::Entity; //! The type used for sizes using size_type = std::size_t; //! Tree of local finite elements / local shape function sets using RootTree = typename RootLocalView::Tree; //! Tree of local finite elements / local shape function sets using Tree = typename TypeTree::ChildForTreePath; /** \brief Construct local view for a given global finite element basis */ SubspaceLocalView(const GlobalBasis& globalBasis, const PrefixPath& prefixPath) : globalBasis_(&globalBasis), rootLocalView_(globalBasis.rootBasis().localView()) { // static_assert(models, Tree>(), "Tree type passed to SubspaceLocalView does not model the BasisNode concept."); } /** \brief Bind the view to a grid element * * Having to bind the view to an element before being able to actually access any of its data members * offers to centralize some expensive setup code in the 'bind' method, which can save a lot of run-time. */ void bind(const Element& e) { rootLocalView_.bind(e); } /** \brief Return the grid element that the view is bound to * * \throws Dune::Exception if the view is not bound to anything */ const Element& element() const { return rootLocalView_.element(); } /** \brief Unbind from the current element * * Calling this method should only be a hint that the view can be unbound. */ void unbind() { rootLocalView_.unbind(); } /** \brief Return the local ansatz tree associated to the bound entity * * \returns Tree // This is tree */ const Tree& tree() const { return TypeTree::child(rootLocalView_.tree(), globalBasis_->prefixPath()); } /** \brief Total number of degrees of freedom on this element */ size_type size() const { return rootLocalView_.size(); } /** * \brief Maximum local size for any element on the GridView * * This is the maximal size needed for local matrices * and local vectors, i.e., the result is */ size_type maxSize() const { return rootLocalView_.maxSize(); } /** \brief Return the global basis that we are a view on */ const GlobalBasis& globalBasis() const { return *globalBasis_; } const RootLocalView& rootLocalView() const { return rootLocalView_; } protected: const GlobalBasis* globalBasis_; RootLocalView rootLocalView_; }; } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_SUBSPACELOCALVIEW_HH dune-functions-2.5.1/dune/functions/functionspacebases/taylorhoodbasis.hh000066400000000000000000000265351313314422100270360ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_TAYLORHOODBASIS_HH #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_TAYLORHOODBASIS_HH #include #include #include #include #include #include #include namespace Dune { namespace Functions { // ***************************************************************************** // This is the reusable part of the basis. It contains // // TaylorHoodNodeFactory // TaylorHoodNodeIndexSet // TaylorHoodBasisTree // TaylorHoodVelocityTree // // The factory allows to create the others and is the owner of possible shared // state. These three components do _not_ depend on the global basis or index // set and can be used without a global basis. // ***************************************************************************** template class TaylorHoodVelocityTree; template class TaylorHoodBasisTree; template class TaylorHoodNodeIndexSet; /** * \brief Factory for lowest order Taylor-Hood basis * * \ingroup FunctionSpaceBasesImplementations * * \tparam GV The grid view that the FE basis is defined on * \tparam MI Type to be used for multi-indices * \tparam HI Flag to select hybrid indices * * \note This mainly serves as an example, since you can construct a factory with * the same functionality manually using * \code * static const int k = 1; * using VelocityFactory = PowerNodeFactory,dim>; * using PressureFactory = PQkNodeFactory; * using TaylorHoodKNodeFactory = CompositeNodeFactory; * \endcode * Where IMS is LeafBlockedInterleaved if HI is set and * FlatInterleaved otherwise. */ template class TaylorHoodNodeFactory { static const bool useHybridIndices = HI; static const int dim = GV::dimension; template friend class TaylorHoodNodeIndexSet; public: //! The grid view that the FE basis is defined on using GridView = GV; //! Type used for indices and size information using size_type = std::size_t; //! Template mapping root tree path to type of created tree node template using Node = TaylorHoodBasisTree; //! Template mapping root tree path to type of created tree node index set template using IndexSet = TaylorHoodNodeIndexSet; //! Type used for global numbering of the basis vectors using MultiIndex = MI; //! Type used for prefixes handed to the size() method using SizePrefix = Dune::ReservedVector; private: using PQMultiIndex = std::array; using PQ1Factory = PQkNodeFactory; using PQ2Factory = PQkNodeFactory; public: //! Constructor for a given grid view object TaylorHoodNodeFactory(const GridView& gv) : gridView_(gv), pq1Factory_(gv), pq2Factory_(gv) {} //! Initialize the global indices void initializeIndices() { pq1Factory_.initializeIndices(); pq2Factory_.initializeIndices(); } //! Obtain the grid view that the basis is defined on const GridView& gridView() const { return gridView_; } //! Update the stored grid view, to be called if the grid has changed void update (const GridView& gv) { pq1Factory_.update(gv); pq2Factory_.update(gv); } /** * \brief Create tree node with given root tree path * * \tparam TP Type of root tree path * \param tp Root tree path * * By passing a non-trivial root tree path this can be used * to create a node suitable for being placed in a tree at * the position specified by the root tree path. */ template Node node(const TP& tp) const { return Node{tp}; } /** * \brief Create tree node index set with given root tree path * * \tparam TP Type of root tree path * \param tp Root tree path * * Create an index set suitable for the tree node obtained * by node(tp). */ template IndexSet indexSet() const { return IndexSet{*this}; } //! Same as size(prefix) with empty prefix size_type size() const { return 2; } //! Return number of possible values for next position in multi index size_type size(const SizePrefix prefix) const { return sizeImp(prefix); } private: template::type = 0> size_type sizeImp(const SizePrefix prefix) const { if (prefix.size() == 0) return 2; if (prefix.size() == 1) { if (prefix[0] == 0) return dim * pq2Factory_.size(); if (prefix[0] == 1) return pq1Factory_.size(); } if (prefix.size() == 2) return 0; assert(false); } template::type = 0> size_type sizeImp(const SizePrefix prefix) const { if (prefix.size() == 0) return 2; if (prefix.size() == 1) { if (prefix[0] == 0) return pq2Factory_.size(); if (prefix[0] == 1) return pq1Factory_.size(); } if (prefix.size() == 2) { if (prefix[0] == 0) return dim; if (prefix[0] == 1) return 0; } if (prefix.size() == 3) return 0; assert(false); } public: //! Get the total dimension of the space spanned by this basis size_type dimension() const { return dim * pq2Factory_.size() + pq1Factory_.size(); } //! Get the maximal number of DOFs associated to node for any element size_type maxNodeSize() const { return dim * pq2Factory_.maxNodeSize() + pq1Factory_.maxNodeSize(); } protected: GridView gridView_; PQ1Factory pq1Factory_; PQ2Factory pq2Factory_; }; template class TaylorHoodVelocityTree : public PowerBasisNode, GV::dimension> { using ComponentTreePath = decltype(TypeTree::push_back(TP(), 0)); using PQ2Node = PQkNode; using Base = PowerBasisNode; public: TaylorHoodVelocityTree(const TP& tp) : Base(tp) { for(int i=0; isetChild(i, std::make_shared(TypeTree::push_back(tp, i))); } }; template class TaylorHoodBasisTree : public CompositeBasisNode(TP()))>, PQkNode(TP()))> > { using VelocityTreePath = decltype(TypeTree::push_back<0ul>(TP())); using PressureTreePath = decltype(TypeTree::push_back<1ul>(TP())); using VelocityNode=TaylorHoodVelocityTree; using PressureNode=PQkNode; using Base=CompositeBasisNode; public: TaylorHoodBasisTree(const TP& tp): Base(tp) { using namespace Dune::TypeTree::Indices; this->template setChild<0>(std::make_shared(push_back(tp, _0))); this->template setChild<1>(std::make_shared(push_back(tp, _1))); } }; template class TaylorHoodNodeIndexSet { static const bool useHybridIndices = HI; static const int dim = GV::dimension; public: using size_type = std::size_t; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = MI; using NodeFactory = TaylorHoodNodeFactory; using Node = typename NodeFactory::template Node; using PQ1TreePath = typename TypeTree::Child::TreePath; using PQ2TreePath = typename TypeTree::Child::TreePath; using PQ1NodeIndexSet = typename NodeFactory::PQ1Factory::template IndexSet; using PQ2NodeIndexSet = typename NodeFactory::PQ2Factory::template IndexSet; TaylorHoodNodeIndexSet(const NodeFactory & nodeFactory) : nodeFactory_(&nodeFactory), pq1NodeIndexSet_(nodeFactory_->pq1Factory_.template indexSet()), pq2NodeIndexSet_(nodeFactory_->pq2Factory_.template indexSet()) {} void bind(const Node& node) { using namespace TypeTree::Indices; node_ = &node; pq1NodeIndexSet_.bind(node.child(_1)); pq2NodeIndexSet_.bind(node.child(_0, 0)); } void unbind() { node_ = nullptr; pq1NodeIndexSet_.unbind(); pq2NodeIndexSet_.unbind(); } size_type size() const { return node_->size(); } MultiIndex index(size_type localIndex) const { return indexImp(localIndex); } template::type = 0> MultiIndex indexImp(size_type localIndex) const { MultiIndex mi; size_type velocityComponentSize = pq2NodeIndexSet_.size(); size_type pressureOffset = velocityComponentSize * dim; mi[0] = localIndex / pressureOffset; if (mi[0] == 0) { size_type v_comp = localIndex / velocityComponentSize; size_type v_localIndex = localIndex % velocityComponentSize; mi[1] = pq2NodeIndexSet_.index(v_localIndex)[0] * dim + v_comp; } if (mi[0] == 1) mi[1] = pq1NodeIndexSet_.index(localIndex-pressureOffset)[0]; return mi; } template::type = 0> MultiIndex indexImp(size_type localIndex) const { MultiIndex mi; size_type velocityComponentSize = pq2NodeIndexSet_.size(); size_type pressureOffset = velocityComponentSize * dim; mi.push_back(localIndex / pressureOffset); if (mi[0] == 0) { size_type v_comp = localIndex / velocityComponentSize; size_type v_localIndex = localIndex % velocityComponentSize; mi.push_back(pq2NodeIndexSet_.index(v_localIndex)[0]); mi.push_back(v_comp); } if (mi[0] == 1) mi.push_back(pq1NodeIndexSet_.index(localIndex-pressureOffset)[0]); return mi; } private: const NodeFactory* nodeFactory_; PQ1NodeIndexSet pq1NodeIndexSet_; PQ2NodeIndexSet pq2NodeIndexSet_; const Node* node_; }; // ***************************************************************************** // This is the actual global basis implementation based on the reusable parts. // ***************************************************************************** /** * \brief Nodal basis for a lowest order Taylor-Hood Lagrangean finite element space * * \ingroup FunctionSpaceBasesImplementations * * \tparam GV The GridView that the space is defined on. * * \note This mainly serves as an example, since you can construct a basis with * the same functionality manually using * \code * static const int k = 1; * auto taylorHoodBasis = makeBasis( * gridView, * composite( * power( * lagrange(), * flatInterleaved()), * lagrange() * )); * \endcode */ template using TaylorHoodBasis = DefaultGlobalBasis> >; } // end namespace Functions } // end namespace Dune #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_TAYLORHOODBASIS_HH dune-functions-2.5.1/dune/functions/functionspacebases/test/000077500000000000000000000000001313314422100242535ustar00rootroot00000000000000dune-functions-2.5.1/dune/functions/functionspacebases/test/.gitignore000066400000000000000000000001571313314422100262460ustar00rootroot00000000000000# temporary files generated by the test system *.log *.trs # individual tests gridviewfunctionspacebasistest dune-functions-2.5.1/dune/functions/functionspacebases/test/CMakeLists.txt000066400000000000000000000006001313314422100270070ustar00rootroot00000000000000# tests that should build and run successfully # Path to the example grid files in dune-grid add_definitions(-DDUNE_GRID_EXAMPLE_GRIDS_PATH=\"${DUNE_GRID_EXAMPLE_GRIDS_PATH}\") dune_add_test(SOURCES gridviewfunctionspacebasistest.cc) dune_add_test(SOURCES taylorhoodbasistest.cc) dune_add_test(SOURCES hierarchicvectorwrappertest.cc) dune_add_test(SOURCES compositebasistest.cc) dune-functions-2.5.1/dune/functions/functionspacebases/test/compositebasistest.cc000066400000000000000000000022761313314422100305150ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include using namespace Dune; int main (int argc, char *argv[]) try { // Set up MPI, if available MPIHelper::instance(argc, argv); /////////////////////////////////// // Generate the grid /////////////////////////////////// const int dim = 2; typedef YaspGrid GridType; FieldVector l(1); std::array elements = {4, 4}; GridType grid(l,elements); typedef GridType::LeafGridView GridView; GridView gridView = grid.leafGridView(); ///////////////////////////////////////////////////////// // Choose a finite element space ///////////////////////////////////////////////////////// using namespace Functions::BasisBuilder; auto basis = makeBasis( gridView, composite( pq<1>(), pq<1>(), pq<1>() )); } // Error handling catch (Exception e) { std::cout << e << std::endl; } dune-functions-2.5.1/dune/functions/functionspacebases/test/gridviewfunctionspacebasistest.cc000066400000000000000000000357521313314422100331220ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Dune; using namespace Dune::Functions; /** \param disableInterpolate Not all bases can correctly represent the linear function * that we use to test whether integrating over a given function gives the correct * value (e.g. basis without dofs on the boundary). Therefore we allow to disable this test. * \param disabledLocalTests Allows to disable certain local tests (see dune-localfunctions/dune/localfunctions/test/test-localfe.hh) */ template void testScalarBasisConst(const Basis& feBasis, bool isPartitionOfUnity, bool disableInterpolate = false, char disabledLocalTests = DisableNone) { static const int dim = Basis::GridView::dimension; ////////////////////////////////////////////////////////////////////////////////////// // Run the dune-localfunctions test for the LocalFiniteElement of each grid element ////////////////////////////////////////////////////////////////////////////////////// typedef typename Basis::GridView GridView; GridView gridView = feBasis.gridView(); typename Basis::LocalView localView(feBasis); // Test the LocalFiniteElement for (auto it = gridView.template begin<0>(); it!=gridView.template end<0>(); ++it) { // Bind the local FE basis view to the current element localView.bind(*it); // The general LocalFiniteElement unit test from dune/localfunctions/test/test-localfe.hh const auto& lFE = localView.tree().finiteElement(); // testFE(lFE, disabledLocalTests); if (lFE.size() != localView.size()) DUNE_THROW(Exception, "Size of leaf node and finite element do not coincide"); } ///////////////////////////////////////////////////////////////////////// // Make sure the basis is a partition of unity ///////////////////////////////////////////////////////////////////////// if (isPartitionOfUnity) { for(const auto& e : elements(gridView)) { // Bind the local FE basis view to the current element localView.bind(e); const auto& lFE = localView.tree().finiteElement(); const QuadratureRule& quad = QuadratureRules::rule(e.type(), 3); std::vector > values; for (size_t i=0; i 1e-5) DUNE_THROW(Exception, "Basis is no partition of unity, even though it is supposed to be! Error occurred for geometry type: " << e.type()); } } } //////////////////////////////////////////////////////////////////////////// // Make sure the basis does not give out constant zero shape functions //////////////////////////////////////////////////////////////////////////// for(const auto& e : elements(gridView)) { // Bind the local FE basis view to the current element localView.bind(e); const auto& lFE = localView.tree().finiteElement(); const QuadratureRule& quad = QuadratureRules::rule(e.type(), 3); std::vector > values; std::vector sumOfAbsValues(lFE.size()); std::fill(sumOfAbsValues.begin(), sumOfAbsValues.end(), 0.0); for (size_t i=0; i(), "MultiIndex must support operator[]"); /////////////////////////////////////////////////////////////////////////////////// // Check whether the global indices are in the correct range, // and whether each global index appears at least once. /////////////////////////////////////////////////////////////////////////////////// std::vector seen(feBasis.size()); std::fill(seen.begin(), seen.end(), false); auto localIndexSet = feBasis.localIndexSet(); // Loop over all leaf elements for (auto it = gridView.template begin<0>(); it!=gridView.template end<0>(); ++it) { // Bind the local FE basis view to the current element localView.bind(*it); localIndexSet.bind(localView); for (size_t i=0; i= seen.size()) DUNE_THROW(Exception, "Local index " << i << " is mapped to global index " << localIndexSet.index(i) << ", which is larger than allowed"); seen[localIndexSet.index(i)[0]] = true; } } for (size_t i=0; i x(feBasis.size()); if (! disableInterpolate) interpolate(feBasis, x, [](FieldVector x){ return x[0]; }); else // dummy values std::fill(x.begin(), x.end(), 0.5); // Objects required in the local context auto localIndexSet2 = feBasis.localIndexSet(); std::vector localCoefficients(localView.maxSize()); // Loop over elements and integrate over the function double integral = 0; for (const auto& element : elements(gridView)) { localView.bind(element); localIndexSet.bind(localView); localIndexSet2.bind(localView); // paranoia checks assert(localView.size() == localIndexSet.size()); assert(&(localView.globalBasis()) == &(feBasis)); assert(&(localIndexSet.localView()) == &(localView)); assert(localIndexSet.size() == localIndexSet2.size()); for (size_t i=0; i::rule(element.type(), 1+tree.finiteElement().localBasis().order()); // Loop over all quadrature points for ( size_t pt=0; pt < quad.size(); pt++ ) { // Position of the current quadrature point in the reference element const FieldVector& quadPos = quad[pt].position(); // The multiplicative factor in the integral transformation formula const double integrationElement = element.geometry().integrationElement(quadPos); // Evaluate all shape function values at this point std::vector > shapeFunctionValues; localFiniteElement.localBasis().evaluateFunction(quadPos, shapeFunctionValues); // Actually compute the vector entries for (size_t i=0; i 1e-10) DUNE_THROW(Dune::Exception, "Error: integral value is wrong!"); } template void testScalarBasis(Basis& feBasis, GV gv, bool isPartitionOfUnity, bool disableInterpolate = false, char disabledLocalTests = DisableNone) { feBasis.update(gv); testScalarBasisConst(feBasis, isPartitionOfUnity, disableInterpolate, disabledLocalTests); } template void testOnStructuredGrid() { std::cout << " +++++++++++ Testing on structured " << dim << "d grids ++++++++++++" << std::endl; // Generate grid for testing typedef YaspGrid GridType; FieldVector l; std::fill(l.begin(), l.end(), 1.0); std::array elements; std::fill(elements.begin(), elements.end(), 2); GridType grid(l,elements); // Test whether PQ1FunctionSpaceBasis.hh can be instantiated on the leaf view typedef typename GridType::LeafGridView GridView; GridView gridView = grid.leafGridView(); PQ1NodalBasis pq1Basis(gridView); PQkNodalBasis pq3Basis(gridView); PQkNodalBasis pq4Basis(gridView); PQkNodalBasis pq0Basis(gridView); LagrangeDGBasis lagrangeDG1Basis(gridView); LagrangeDGBasis lagrangeDG2Basis(gridView); LagrangeDGBasis lagrangeDG3Basis(gridView); grid.globalRefine(2); // Test PQ1NodalBasis testScalarBasis(pq1Basis, gridView, true); // Test PQkNodalBasis for k==3 if (dim<3) // Currently not implemented for dim >= 3 testScalarBasis(pq3Basis, gridView, true); // Test PQkNodalBasis for k==4 if (dim<3) // Currently not implemented for dim >= 3 testScalarBasis(pq4Basis, gridView, true); // Test PQkNodalBasis for the corner case k == 0 testScalarBasis(pq0Basis, gridView, true); // Test LagrangeDGBasis for k==1 testScalarBasis(lagrangeDG1Basis, gridView, true); // Test LagrangeDGBasis for k==2 testScalarBasis(lagrangeDG2Basis, gridView, true); // Test LagrangeDGBasis for k==3 testScalarBasis(lagrangeDG3Basis, gridView, true); // Testing B-spline basis with open knot vectors std::vector knotVector(elements[0]*4+1); for (size_t i=0; i bSplineBasis(gridView, knotVector, order); testScalarBasisConst(bSplineBasis, true, true, // Don't interpolate a given function and try to integrate over it DisableLocalInterpolation); } // Testing B-spline basis with non-open knot vectors std::cout << " Testing B-spline basis with non-open knot vectors" << std::endl; for (unsigned int order : {0, 1, 2}) { std::cout << " order: " << order << std::endl; BSplineBasis bSplineBasis(gridView, knotVector, order, false); testScalarBasisConst(bSplineBasis, order==0, // only zero-order B-splines for a partition of unity true, // Don't interpolate a given function and try to integrate over it DisableLocalInterpolation); } } template void testOnHybridGrid() { #if ! HAVE_UG std::cout << " ---- Skipping test on hybrid " << dim << "d grid -- UGGrid is not installed ----" << std::endl; #else std::cout << " +++++++++++ Testing on hybrid " << dim << "d grid ++++++++++++" << std::endl; // Generate grid for testing typedef UGGrid GridType; const std::string path = std::string(DUNE_GRID_EXAMPLE_GRIDS_PATH) + "gmsh/"; std::string filename = path + "hybrid-testgrid-" + std::to_string(dim) + "d.msh"; std::shared_ptr grid(GmshReader::read(filename)); // Test whether function space basis can be instantiated on the leaf view typedef typename GridType::LeafGridView GridView; GridView gridView = grid->leafGridView(); // Disable the global interpolation test for 3d grids. // Global interpolation should work for all grids and spaces, but the hard-coded // reference value is wrong. bool disableInterpolate = (dim==3); // Test PQ1NodalBasis -- dedicated implementation PQ1NodalBasis pq1DedicatedBasis(gridView); testScalarBasisConst(pq1DedicatedBasis, true, disableInterpolate); // Test PQ1NodalBasis -- generic basis PQkNodalBasis pq1Basis(gridView); testScalarBasisConst(pq1Basis, true, disableInterpolate); // Test PQkNodalBasis for k==3 PQkNodalBasis pq3Basis(gridView); if (dim<3) // Currently not implemented for dim >= 3 testScalarBasisConst(pq3Basis, true, disableInterpolate); // Test PQkNodalBasis for k==4 PQkNodalBasis pq4Basis(gridView); if (dim<3) // Currently not implemented for dim >= 3 testScalarBasisConst(pq4Basis, true, disableInterpolate); // Test LagrangeDGBasis for k==1 LagrangeDGBasis lagrangeDG1Basis(gridView); testScalarBasisConst(lagrangeDG1Basis, true, disableInterpolate); // Test LagrangeDGBasis for k==2 // \todo Enable these tests once pyramid element of order two is bug free // LagrangeDGBasis lagrangeDG2Basis(gridView); // testScalarBasisConst(lagrangeDG2Basis, true, disableInterpolate); // Test LagrangeDGBasis for k==3 // \todo Enable these tests once pyramid element of order three is implemented // LagrangeDGBasis lagrangeDG3Basis(gridView); // testScalarBasisConst(lagrangeDG3Basis, true, disableInterpolate); #endif } int main (int argc, char* argv[]) try { Dune::MPIHelper::instance(argc, argv); testOnStructuredGrid<1>(); testOnStructuredGrid<2>(); testOnStructuredGrid<3>(); testOnHybridGrid<2>(); testOnHybridGrid<3>(); return 0; } catch ( Dune::Exception &e ) { std::cerr << "Dune reported error: " << e << std::endl; return 1; } catch(...) { std::cerr << "Unknown exception thrown!" << std::endl; return 1; } dune-functions-2.5.1/dune/functions/functionspacebases/test/hierarchicvectorwrappertest.cc000066400000000000000000000203051313314422100324070ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Dune; /** * \brief A Dummy size provider * * This is a mock class providing non-uniform size information. * It's non-uniform in the sense, that not all multi-indices are * do not always have the same size. */ template class HybridSizeInfoDummy { public: using size_type = std::size_t; using SizePrefix = Dune::ReservedVector; /** * \brief Construct from basis */ HybridSizeInfoDummy() {} /** * \brief Return number possible values for next position in multi index */ size_type operator()(const SizePrefix& prefix) const { return size(prefix); } /** * \brief Return number possible values for next position in multi index * * This shall vanish. It's just here such that this can be used * as size provider n place of the basis. */ size_type size(const SizePrefix& prefix) const { if (prefix.size() == 0) return 2; if (prefix.size() == 1) { if (prefix[0] == 0) return 23; if (prefix[0] == 1) return 42; } if (prefix.size() == 2) { if (prefix[0] == 0) return dim; if (prefix[0] == 1) return 0; } if (prefix.size() == 3) return 0; assert(false); } operator size_type () const { return 23*dim+42; } }; #if 0 template::value, int>::type = 0> bool checkHierarchicVectorSize(const Vector& v, const SizeInfo& sizeInfo, SizePrefix prefix) { TestSuite test;; test.require(v.size() == sizeInfo(SizePrefix{})) prefix.push_back(0); for (std::size_t i=0; i< v.size(); ++i) { prefix.back() = i; test.check(checkHierarchicVectorSize(v[i], sizeInfo, prefix)) << "Size check for entry with prefix " << prefix << " failed"; } return test; } template bool checkHierarchicVectorSize(const Vector& v, const SizeInfo& sizeInfo, SizePrefix prefix) { TestSuite test;; test.require(v.size() == sizeInfo(SizePrefix{})) prefix.push_back(0); for (std::size_t i=0; i< v.size(); ++i) { prefix.back() = i; test.check(checkHierarchicVectorSize(v[i], sizeInfo, prefix)) << "Size check for entry with prefix " << prefix << " failed"; } return test; } #endif template Dune::TestSuite checkHierarchicVector(std::string shortName="") { Dune::TestSuite test(shortName); using namespace Dune::TypeTree::Indices; using SizeInfo = HybridSizeInfoDummy; using SizePrefix = typename SizeInfo::SizePrefix; SizeInfo sizeInfo; // Create raw vector Vector x_raw; // Create wrapped vector Dune::Functions::HierarchicVectorWrapper x(x_raw); // Resize wrapped vector using sizeInfo x.resize(sizeInfo); // Derive size information from vector test.require(x_raw.size() == sizeInfo(SizePrefix{}), "resize check") << "x_raw.size() is " << x_raw.size() << " but should be " << sizeInfo(SizePrefix{}); test.require(x_raw[_0].size() == sizeInfo(SizePrefix{0}), "resize check") << "x_raw[_0].size() is " << x_raw[_0].size() << " but should be " << sizeInfo(SizePrefix{0}); for (std::size_t i=0; i>; using PressureVector = std::vector; using Coefficient = double; using Vector = Functions::TupleVector; using MultiIndex = ReservedVector; test.subTest(checkHierarchicVector("TV>, V>")); } { using VelocityVector = std::vector>>; using PressureVector = std::vector>; using Coefficient = double; using Vector = Functions::TupleVector; using MultiIndex = ReservedVector; test.subTest(checkHierarchicVector("TV>>, V>>")); } { using VelocityVector = std::vector>>; using PressureVector = std::vector>; using Coefficient = Dune::FieldVector; using Vector = Functions::TupleVector; using MultiIndex = ReservedVector; test.subTest(checkHierarchicVector("TV>>, V>>")); } { static const std::size_t dim = 5; using VelocityVector = std::vector,dim>>; using PressureVector = std::vector; using Coefficient = double; using Vector = Functions::TupleVector; using MultiIndex = ReservedVector; test.subTest(checkHierarchicVector("TV,5>>, V>")); } { static const std::size_t dim = 5; using VelocityVector = Dune::BlockVector>; using PressureVector = Dune::BlockVector>; using Coefficient = double; using Vector = Dune::MultiTypeBlockVector; using MultiIndex = ReservedVector; test.subTest(checkHierarchicVector("MTBV>, BV>>")); } { static const std::size_t dim = 3; using VelocityVector = std::vector, double, Dune::FieldVector>>; using PressureVector = Dune::BlockVector>; using Coefficient = double; using Vector = Dune::MultiTypeBlockVector; using MultiIndex = ReservedVector; test.subTest(checkHierarchicVector("MTBV, double, FV>>, BV>")); } return test.exit(); } // Error handling catch (Exception e) { std::cout << e << std::endl; return 1; } dune-functions-2.5.1/dune/functions/functionspacebases/test/taylorhoodbasistest.cc000066400000000000000000000075421313314422100307000ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include using namespace Dune; using namespace Dune::Functions; int main (int argc, char* argv[]) try { Dune::MPIHelper::instance(argc, argv); // Generate grid for testing const int dim = 2; typedef YaspGrid GridType; FieldVector l(1); std::array elements = {{10, 10}}; GridType grid(l,elements); typedef GridType::LeafGridView GridView; typedef TaylorHoodBasis Basis; const GridView& gridView = grid.leafGridView(); Basis feBasis(gridView); typedef Basis::MultiIndex MultiIndex; // Sample the function f(x,y) = x on the grid vertices // If we use that as the coefficients of a finite element function, // we know its integral and can check whether quadrature returns // the correct result std::array,dim> x; for (unsigned int i = 0; i(); it != gridView.end(); ++it) x[1][gridView.indexSet().index(*it)] = it->geometry().corner(0)[0]; // Objects required in the local context auto localView = feBasis.localView(); auto localIndexSet = feBasis.localIndexSet(); std::vector coefficients(localView.maxSize()); // Loop over elements and integrate over the function double integral = 0; for (auto it = gridView.begin<0>(); it != gridView.end<0>(); ++it) { localView.bind(*it); localIndexSet.bind(localView); // paranoia checks assert(localView.size() == localIndexSet.size()); assert(&(localView.globalBasis()) == &(feBasis)); assert(&(localIndexSet.localView()) == &(localView)); // copy data from global vector coefficients.resize(localIndexSet.size()); for (size_t i=0; i& quad = QuadratureRules::rule(it->type(), 1); // Loop over all quadrature points for ( size_t pt=0; pt < quad.size(); pt++ ) { // Position of the current quadrature point in the reference element const FieldVector& quadPos = quad[pt].position(); // The multiplicative factor in the integral transformation formula const double integrationElement = it->geometry().integrationElement(quadPos); // Evaluate all shape function values at this point std::vector > shapeFunctionValues; localFiniteElement.localBasis().evaluateFunction(quadPos, shapeFunctionValues); // Actually compute the vector entries for (size_t i=0; i #include #include #include #include #include #include #include #include namespace Dune { namespace Functions { namespace Imp { template class DerivativeTraits=DefaultDerivativeTraits> class LocalAnalyticGridViewFunction; template class DerivativeTraits> class LocalAnalyticGridViewFunction { public: using Signature = Range(LocalDomain); using RawSignature = typename SignatureTraits::RawSignature; using DerivativeSignature = typename DerivativeTraits::Range(LocalDomain); using GridView = GV; using EntitySet = GridViewEntitySet; using Element = typename EntitySet::Element; // using Geometry = typename Element::Geometry; using Geometry = typename std::decay::type; // Use the inderiction via derivativeIfImplemented to also support // function types F that do not implement derivative. In this case // the interface type DifferentiableFunction is used a dummy for // the derivative type using DerivativeDummy = DifferentiableFunction; using GlobalRawDerivative = decltype(Imp::derivativeIfImplemented(std::declval())); using LocalDerivative = LocalAnalyticGridViewFunction; template = 0> LocalAnalyticGridViewFunction(FT&& f) : f_(std::forward(f)) {} void bind(const Element& element) { element_ = element; // We'd like to do // // geometry_ = element_.geometry(); // // But since Geometry is not assignable we // have to reconstruct it - argh geometry_.release(); geometry_.emplace(element_.geometry()); } void unbind() {} Range operator()(const LocalDomain& x) const { return f_(geometry_.value().global(x)); } const Element& localContext() const { return element_; } friend LocalDerivative derivative(const LocalAnalyticGridViewFunction& t) { return LocalDerivative(Imp::derivativeIfImplemented(t.f_)); } private: // Hack around the fact that Geometry is not default constructible. Optional geometry_; Element element_; F f_; }; } // end namespace Imp template class DerivativeTraits=DefaultDerivativeTraits> class AnalyticGridViewFunction; /** * \brief Class wrapping any differentiable function as grid function * * \ingroup FunctionImplementations */ template class DerivativeTraits> class AnalyticGridViewFunction { public: using Signature = Range(Domain); using RawSignature = typename SignatureTraits::RawSignature; using DerivativeSignature = typename DerivativeTraits::Range(Domain); using GridView = GV; using EntitySet = GridViewEntitySet; using Element = typename EntitySet::Element; using Geometry = typename Element::Geometry; // Use the inderiction via derivativeIfImplemented to also support // function types F that do not implement derivative. In this case // the interface type DifferentiableFunction is used a dummy for // the derivative type using DerivativeDummy = DifferentiableFunction; using GlobalRawDerivative = decltype(Imp::derivativeIfImplemented(std::declval())); using Derivative = AnalyticGridViewFunction; using LocalDomain = typename EntitySet::LocalCoordinate; using LocalFunction = typename Imp::LocalAnalyticGridViewFunction::template Traits>; template AnalyticGridViewFunction(FT&& f, const GridView& gridView) : f_(std::forward(f)), entitySet_(gridView) {} Range operator()(const Domain& x) const { return f_(x); } friend Derivative derivative(const AnalyticGridViewFunction& t) { return Derivative(Imp::derivativeIfImplemented(t.f_), t.entitySet_.gridView()); } friend LocalFunction localFunction(const AnalyticGridViewFunction& t) { return LocalFunction(t.f_); } const EntitySet& entitySet() const { return entitySet_; } private: F f_; EntitySet entitySet_; }; /** * \brief Construct AnalyticGridViewFunction from function and grid view * * The returned function supports localFunction() and stores a copy of the * original function. * * \param f A function object supporting argument compatible with global coordinates * \param gridView The GridView the function should act on. * * \returns A function that models the GridFunction interface. */ template AnalyticGridViewFunction< typename std::result_of::Geometry::GlobalCoordinate)>::type // Range (typename GridView::template Codim<0>::Geometry::GlobalCoordinate), // Domain GridView, typename std::decay::type > // Raw type of F (without & or &&) makeAnalyticGridViewFunction(F&& f, const GridView& gridView) { using Domain = typename GridView::template Codim<0>::Geometry::GlobalCoordinate; using Range = typename std::result_of::type; using FRaw = typename std::decay::type; return AnalyticGridViewFunction(std::forward(f), gridView); } }} // namespace Dune::Functions #endif // DUNE_FUNCTIONS_GRIDFUNCTIONS_ANALYTICGRIDVIEWFUNCTION_HH dune-functions-2.5.1/dune/functions/gridfunctions/discreteglobalbasisfunction.hh000066400000000000000000000323171313314422100303750ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_GRIDFUNCTIONS_DISCRETEGLOBALBASISFUNCTIONS_HH #define DUNE_FUNCTIONS_GRIDFUNCTIONS_DISCRETEGLOBALBASISFUNCTIONS_HH #include #include #include #include #include #include #include namespace Dune { namespace Functions { /** * \brief A grid function induced by a global basis and a coefficient vector * * \ingroup FunctionImplementations * * This implements the grid function interface by combining a given global * basis and a coefficient vector. The part of the spanned space that should * be covered by the function is determined by a tree path that specifies the * corresponding local ansatz tree. * * This class supports mapping of subtrees to multi-component ranges, * vector-valued shape functions, and implicit product spaces given * by vector-valued coefficients. The mapping of these to the range * type is done via the following multistage procedure: * * 1.Each leaf node N in the local ansatz subtree is associated to an entry * RE of the range-type via the given node-to-range-entry-map. * * Now let C be the coefficient block for a single basis function and * V the value of this basis function at the evaluation point. Notice * that both may be scalar, vector, matrix, or general container valued. * * 2.Each entry of C is associated with a flat index j via FlatVectorBackend. * This is normally a lexicographic index. The total scalar dimension according * to those flat indices is dim(C). * 3.Each entry of V is associated with a flat index k via FlatVectorBackend. * This is normally a lexicographic index. The total scalar dimension according * to those flat indices dim(V). * 4.Each entry of RE is associated with a flat index k via FlatVectorBackend. * This is normally a lexicographic index. The total scalar dimension according * to those flat indices dim(RE). * 5.Via those flat indices we now interpret C,V, and RE as vectors and compute the diadic * product (C x V). The entries of this product are mapped to the flat indices for * RE lexicographically. I.e. we set * * RE[j*dim(V)+k] = C[j] * V[k] * * Hence the range entry RE must have dim(RE) = dim(C)*dim(V). * * \tparam B Type of lobal basis * \tparam TP Type of tree path specifying the requested subtree of ansatz functions * \tparam V Type of coefficient vectors * \tparam NTRE Type of node-to-range-entry-map that associates each leaf node in the local ansatz subtree with an entry in the range type * \tparam R Range type of this function */ template().localView().tree().child(std::declval()))>::type>, typename R = typename V::value_type> class DiscreteGlobalBasisFunction { public: using Basis = B; using TreePath = TP; using Vector = V; using GridView = typename Basis::GridView; using EntitySet = GridViewEntitySet; using Tree = typename Basis::LocalView::Tree; using SubTree = typename TypeTree::ChildForTreePath; using NodeToRangeEntry = NTRE; using Domain = typename EntitySet::GlobalCoordinate; using Range = R; using LocalDomain = typename EntitySet::LocalCoordinate; using Element = typename EntitySet::Element; using Traits = Imp::GridFunctionTraits; class LocalFunction { using LocalBasisView = typename Basis::LocalView; using LocalIndexSet = typename Basis::LocalIndexSet; using size_type = typename SubTree::size_type; template using LocalBasisRange = typename Node::FiniteElement::Traits::LocalBasisType::Traits::RangeType; template using NodeData = typename std::vector>; using ShapeFunctionValueContainer = TreeData; struct LocalEvaluateVisitor : public TypeTree::TreeVisitor , public TypeTree::DynamicTraversal { LocalEvaluateVisitor(const LocalDomain& x, Range& y, const LocalIndexSet& localIndexSet, const Vector& coefficients, const NodeToRangeEntry& nodeToRangeEntry, ShapeFunctionValueContainer& shapeFunctionValueContainer): x_(x), y_(y), localIndexSet_(localIndexSet), coefficients_(coefficients), nodeToRangeEntry_(nodeToRangeEntry), shapeFunctionValueContainer_(shapeFunctionValueContainer) {} template void leaf(Node& node, TreePath treePath) { using LocalBasisRange = typename Node::FiniteElement::Traits::LocalBasisType::Traits::RangeType; using MultiIndex = typename LocalIndexSet::MultiIndex; using CoefficientBlock = typename std::decay()[std::declval()])>::type; using RangeBlock = typename std::decay::type; auto&& fe = node.finiteElement(); auto&& localBasis = fe.localBasis(); auto&& shapeFunctionValues = shapeFunctionValueContainer_[node]; localBasis.evaluateFunction(x_, shapeFunctionValues); // Get range entry associated to this node auto&& re = nodeToRangeEntry_(node, y_); for (size_type i = 0; i < localBasis.size(); ++i) { auto&& multiIndex = localIndexSet_.index(node.localIndex(i)); // Get coefficient associated to i-th shape function auto&& c = coefficients_[multiIndex]; // Get value of i-th shape function auto&& v = shapeFunctionValues[i]; // Notice that the range entry re, the coefficient c, and the shape functions // value v may all be scalar, vector, matrix, or general container valued. // The matching of their entries is done via the multistage procedure described // in the class documentation of DiscreteGlobalBasisFunction. auto dimC = FlatVectorBackend::size(c); auto dimV = FlatVectorBackend::size(v); assert(dimC*dimV == FlatVectorBackend::size(re)); for(size_type j=0; j::getEntry(c, j); for(size_type k=0; k::getEntry(v, k); FlatVectorBackend::getEntry(re, j*dimV + k) += c_j*v_k; } } } } const LocalDomain& x_; Range& y_; const LocalIndexSet& localIndexSet_; const Vector& coefficients_; const NodeToRangeEntry& nodeToRangeEntry_; ShapeFunctionValueContainer& shapeFunctionValueContainer_; }; public: using GlobalFunction = DiscreteGlobalBasisFunction; using Domain = LocalDomain; using Range = GlobalFunction::Range; using Element = GlobalFunction::Element; LocalFunction(const DiscreteGlobalBasisFunction& globalFunction) : globalFunction_(&globalFunction) , localBasisView_(globalFunction.basis().localView()) , localIndexSet_(globalFunction.basis().localIndexSet()) { // Here we assume that the tree can be accessed, traversed, // and queried for tree indices even in unbound state. subTree_ = &TypeTree::child(localBasisView_.tree(), globalFunction_->treePath()); shapeFunctionValueContainer_.init(*subTree_); // localDoFs_.reserve(localBasisView_.maxSize()); } LocalFunction(const LocalFunction& other) : globalFunction_(other.globalFunction_) , localBasisView_(globalFunction_->basis().localView()) , localIndexSet_(globalFunction_->basis().localIndexSet()) { // Here we assume that the tree can be accessed, traversed, // and queried for tree indices even in unbound state. subTree_ = &TypeTree::child(localBasisView_.tree(), globalFunction_->treePath()); shapeFunctionValueContainer_.init(*subTree_); } LocalFunction operator=(const LocalFunction& other) { globalFunction_ = other.globalFunction_; localBasisView_ = other.localBasisView_; localIndexSet_ = other.localIndexSet_; subTree_ = &TypeTree::child(localBasisView_.tree(), globalFunction_->treePath()); // Here we assume that the tree can be accessed, traversed, // and queried for tree indices even in unbound state. shapeFunctionValueContainer_.init(*subTree_); } /** * \brief Bind LocalFunction to grid element. * * You must call this method before evaluate() * and after changes to the coefficient vector. */ void bind(const Element& element) { localBasisView_.bind(element); localIndexSet_.bind(localBasisView_); // Read dofs associated to bound element // localDoFs_.resize(subTree.size()); // for (size_type i = 0; i < subTree.size(); ++i) // localDoFs_[i] = globalFunction_->dofs()[localIndexSet_.index(i)]; } void unbind() { localIndexSet_.unbind(); localBasisView_.unbind(); } /** * \brief Evaluate LocalFunction at bound element. * * The result of this method is undefined if you did * not call bind() beforehand or changed the coefficient * vector after the last call to bind(). In the latter case * you have to call bind() again in order to make operator() * usable. */ Range operator()(const Domain& x) const { auto y = Range(0); LocalEvaluateVisitor localEvaluateVisitor(x, y, localIndexSet_, globalFunction_->dofs(), globalFunction_->nodeToRangeEntry(), shapeFunctionValueContainer_); TypeTree::applyToTree(*subTree_, localEvaluateVisitor); return y; } const Element& localContext() const { return localBasisView_.element(); } friend typename Traits::LocalFunctionTraits::DerivativeInterface derivative(const LocalFunction& t) { DUNE_THROW(NotImplemented,"not implemented"); } private: const DiscreteGlobalBasisFunction* globalFunction_; LocalBasisView localBasisView_; LocalIndexSet localIndexSet_; mutable ShapeFunctionValueContainer shapeFunctionValueContainer_; // std::vector localDoFs_; const SubTree* subTree_; }; DiscreteGlobalBasisFunction(const Basis & basis, const TreePath& treePath, const V & coefficients, const NodeToRangeEntry& nodeToRangeEntry) : entitySet_(basis.gridView()), basis_(stackobject_to_shared_ptr(basis)), treePath_(treePath), coefficients_(stackobject_to_shared_ptr(coefficients)), nodeToRangeEntry_(stackobject_to_shared_ptr(nodeToRangeEntry)) {} DiscreteGlobalBasisFunction(std::shared_ptr basis, const TreePath& treePath, std::shared_ptr coefficients, std::shared_ptr nodeToRangeEntry) : entitySet_(basis->gridView()), basis_(basis), treePath_(treePath), coefficients_(coefficients), nodeToRangeEntry_(nodeToRangeEntry) {} const Basis& basis() const { return *basis_; } const TreePath& treePath() const { return treePath_; } const V& dofs() const { return *coefficients_; } const NodeToRangeEntry& nodeToRangeEntry() const { return *nodeToRangeEntry_; } // TODO: Implement this using hierarchic search Range operator() (const Domain& x) const { DUNE_THROW(NotImplemented,"not implemented"); } friend typename Traits::DerivativeInterface derivative(const DiscreteGlobalBasisFunction& t) { DUNE_THROW(NotImplemented,"not implemented"); } friend LocalFunction localFunction(const DiscreteGlobalBasisFunction& t) { return LocalFunction(t); } /** * \brief Get associated EntitySet */ const EntitySet& entitySet() const { return entitySet_; } private: EntitySet entitySet_; std::shared_ptr basis_; const TreePath treePath_; std::shared_ptr coefficients_; std::shared_ptr nodeToRangeEntry_; }; template auto makeDiscreteGlobalBasisFunction(B&& basis, const TP& treePath, V&& vector) { using Basis = std::decay_t; using Vector = std::decay_t; using NTREM = DefaultNodeToRangeMap>; auto nodeToRangeEntryPtr = std::make_shared(makeDefaultNodeToRangeMap(basis, treePath)); auto basisPtr = Dune::wrap_or_move(std::forward(basis)); auto vectorPtr = Dune::wrap_or_move(std::forward(vector)); return DiscreteGlobalBasisFunction(basisPtr, treePath, vectorPtr, nodeToRangeEntryPtr); } template auto makeDiscreteGlobalBasisFunction(B&& basis, V&& vector) { return makeDiscreteGlobalBasisFunction(std::forward(basis), TypeTree::hybridTreePath(), std::forward(vector)); } } // namespace Functions } // namespace Dune #endif // DUNE_FUNCTIONS_GRIDFUNCTIONS_DISCRETEGLOBALBASISFUNCTIONS_HH dune-functions-2.5.1/dune/functions/gridfunctions/discretescalarglobalbasisfunction.hh000066400000000000000000000132501313314422100315560ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_GRIDFUNCTIONS_DISCRETESCALARGLOBALBASISFUNCTIONS_HH #define DUNE_FUNCTIONS_GRIDFUNCTIONS_DISCRETESCALARGLOBALBASISFUNCTIONS_HH #include #include #include #include #include namespace Dune { namespace Functions { /** * \brief A grid function induced by a global basis and a coefficient vector * * \ingroup FunctionImplementations * * \deprecated This class is deprecated. Please use DiscreteGlobalBasisFunction instead! */ template class DUNE_DEPRECATED_MSG("Use DiscreteGlobalBasisFunction instead!") DiscreteScalarGlobalBasisFunction { public: using GridView = typename Basis::GridView; using EntitySet = GridViewEntitySet; using Domain = typename EntitySet::GlobalCoordinate; using Range = typename V::value_type; using LocalBasisRange = typename Basis::LocalView::Tree::FiniteElement::Traits::LocalBasisType::Traits::RangeType; using LocalDomain = typename EntitySet::LocalCoordinate; using Element = typename EntitySet::Element; using Traits = Imp::GridFunctionTraits; class LocalFunction { using LocalBasisView = typename Basis::LocalView; using LocalIndexSet = typename Basis::LocalIndexSet; using size_type = typename LocalBasisView::Tree::size_type; public: using GlobalFunction = DiscreteScalarGlobalBasisFunction; using Domain = LocalDomain; using Range = GlobalFunction::Range; using Element = GlobalFunction::Element; LocalFunction(const DiscreteScalarGlobalBasisFunction& globalFunction) : globalFunction_(&globalFunction) , localBasisView_(globalFunction.basis().localView()) , localIndexSet_(globalFunction.basis().localIndexSet()) { localDoFs_.reserve(localBasisView_.maxSize()); shapeFunctionValues_.reserve(localBasisView_.maxSize()); } /** * \brief Bind LocalFunction to grid element. * * You must call this method before evaluate() * and after changes to the coefficient vector. */ void bind(const Element& element) { localBasisView_.bind(element); localIndexSet_.bind(localBasisView_); // Read dofs associated to bound element localDoFs_.resize(localIndexSet_.size()); for (size_type i = 0; i < localIndexSet_.size(); ++i) localDoFs_[i] = globalFunction_->dofs()[localIndexSet_.index(i)[0]]; // Prepare result vector for shape function shapeFunctionValues_.resize(localIndexSet_.size()); } void unbind() { localIndexSet_.unbind(); localBasisView_.unbind(); } /** * \brief Evaluate LocalFunction at bound element. * * The result of this method is undefined if you did * not call bind() beforehand or changed the coefficient * vector after the last call to bind(). In the latter case * you have to call bind() again in order to make operator() * usable. */ Range operator()(const Domain& x) const { auto y = Range(0); auto& basis = localBasisView_.tree().finiteElement().localBasis(); basis.evaluateFunction(x, shapeFunctionValues_); for (size_type i = 0; i < basis.size(); ++i) { // Here we essentially want to do // // y += localDoFs_[i] * shapeFunctionValues_[i]; // // Currently we support vector valued coefficients and scalar // local basis functions only. In order to generalize this we // have to use a more general product implementation here. // Maybe we want do adopt the framework of dune-fufem. auto yy = localDoFs_[i]; yy *= shapeFunctionValues_[i]; y += yy; } return y; } const Element& localContext() const { return localBasisView_.element(); } friend typename Traits::LocalFunctionTraits::DerivativeInterface derivative(const LocalFunction& t) { DUNE_THROW(NotImplemented,"not implemented"); } private: const DiscreteScalarGlobalBasisFunction* globalFunction_; LocalBasisView localBasisView_; LocalIndexSet localIndexSet_; std::vector localDoFs_; mutable std::vector shapeFunctionValues_; }; DiscreteScalarGlobalBasisFunction(const Basis & basis, const V & dofs) : entitySet_(basis.gridView()) , basis_(stackobject_to_shared_ptr(basis)) , dofs_(stackobject_to_shared_ptr(dofs)) {} DiscreteScalarGlobalBasisFunction(std::shared_ptr basis, std::shared_ptr dofs) : entitySet_(basis.gridView()) , basis_(basis) , dofs_(dofs) {} const Basis& basis() const { return *basis_; } const V& dofs() const { return *dofs_; } // TODO: Implement this using hierarchic search Range operator() (const Domain& x) const { DUNE_THROW(NotImplemented,"not implemented"); } friend typename Traits::DerivativeInterface derivative(const DiscreteScalarGlobalBasisFunction& t) { DUNE_THROW(NotImplemented,"not implemented"); } friend LocalFunction localFunction(const DiscreteScalarGlobalBasisFunction& t) { return LocalFunction(t); } /** * \brief Get associated EntitySet */ const EntitySet& entitySet() const { return entitySet_; } private: EntitySet entitySet_; std::shared_ptr basis_; std::shared_ptr dofs_; }; } // namespace Functions } // namespace Dune #endif // DUNE_FUNCTIONS_GRIDFUNCTIONS_DISCRETESCALARGLOBALBASISFUNCTIONS_HH dune-functions-2.5.1/dune/functions/gridfunctions/gridfunction.hh000066400000000000000000000127601313314422100253150ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_GRIDFUNCTIONS_GRID_FUNCTION_HH #define DUNE_FUNCTIONS_GRIDFUNCTIONS_GRID_FUNCTION_HH #include #include #include #include #include #include #include #include #include namespace Dune { namespace Functions { /* * Default implementation is empty * The actual implementation is only given if Signature is an type * describing a function signature as Range(Domain). */ template class DerivativeTraits=DefaultDerivativeTraits, size_t bufferSize=56> class GridFunction {}; namespace Imp { /// Traits class providing type information for DifferentiableFunction template class DerivativeTraits, size_t bufferSize> struct GridFunctionTraits : DifferentiableFunctionTraits { protected: using Base=DifferentiableFunctionTraits; public: /// EntitySet the GridFunction lives on using EntitySet = ES; /// Element type of EntitySet using Element = typename EntitySet::Element; /// Signature of the derivative using DerivativeSignature = typename Base::DerivativeSignature; /// Interface type of the derivative using DerivativeInterface = GridFunction; /// Signature of the derivative using LocalSignature = typename Base::Range(typename EntitySet::LocalCoordinate); template using LocalDerivativeTraits = typename Dune::Functions::LocalDerivativeTraits::template Traits; /// LocalFunctionTraits associated with this type using LocalFunctionTraits = typename Dune::Functions::Imp::LocalFunctionTraits; /// Interface type of the local function using LocalFunctionInterface = LocalFunction; /// Internal concept type for type erasure using Concept = GridFunctionWrapperInterface; /// Internal model template for type erasure template using Model = GridFunctionWrapperImplementation; }; } /** * \brief Wrapper class for functions defined on a Grid * * \ingroup FunctionInterface * * Being defined on a grid means in particular that you can evaluate the function * in local coordinates of a given entities of the grid. The set of the entities * this function is defined on is given by an EntitySet. * * This models the \ref Concept::GridFunction concept. */ template class DerivativeTraits, size_t bufferSize> class GridFunction : public TypeErasureBase< typename Imp::GridFunctionTraits::Concept, Imp::GridFunctionTraits::template Model> { using Traits = Imp::GridFunctionTraits; using Base = TypeErasureBase; using DerivativeInterface = typename Traits::DerivativeInterface; using LocalFunctionInterface = typename Traits::LocalFunctionInterface; using EntitySet = typename Traits::EntitySet; public: /** * \brief Construct from function * * \tparam F Function type * * \param f Function of type F * * Calling derivative(DifferentiableFunction) will result in an exception * if the passed function does provide a free derivative() function * found via ADL. */ template = 0 > GridFunction(F&& f) : Base(std::forward(f)) { static_assert(Dune::Functions::Concept::isGridFunction(), "Trying to construct a GridFunction from type that does not model the GridFunction concept"); } GridFunction() = default; /** * \brief Evaluation of wrapped function */ Range operator() (const Domain& x) const { return this->asInterface().operator()(x); } /** * \copydoc DifferentiableFunction::derivative */ friend DerivativeInterface derivative(const GridFunction& t) { return t.asInterface().derivative(); } /** * \brief Get local function of wrapped function * * This is free function will be found by ADL. * * Notice that the returned LocalFunction can * only be used after it has been bound to a * proper local context. */ friend LocalFunctionInterface localFunction(const GridFunction& t) { return t.asInterface().wrappedLocalFunction(); } /** * \brief Get associated EntitySet * * This is free function will be found by ADL. */ const EntitySet& entitySet() const { return this->asInterface().wrappedEntitySet(); } }; }} // namespace Dune::Functions #endif // DUNE_FUNCTIONS_GRIDFUNCTIONS_GRID_FUNCTION_HH dune-functions-2.5.1/dune/functions/gridfunctions/gridfunction_imp.hh000066400000000000000000000035431313314422100261610ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_GRIDFUNCTIONS_GRID_FUNCTION_IMP_HH #define DUNE_FUNCTIONS_GRIDFUNCTIONS_GRID_FUNCTION_IMP_HH #include #include #include namespace Dune { namespace Functions { namespace Imp { /** * A concept describing types that have a localFunction() method found by ADL */ struct HasFreeLocalFunction { template auto require(F&& f) -> decltype( localFunction(f) ); }; // Interface of type erasure wrapper // // Notice that the basic interface of polymorphic classes (destructor, clone, ...) // will be added by the type erasure foundation classes. template class GridFunctionWrapperInterface : public DifferentiableFunctionWrapperInterface { public: virtual LocalFunctionInterface wrappedLocalFunction() const = 0; virtual const EntitySet& wrappedEntitySet() const = 0; }; // Implementation of type erasure wrapper template class GridFunctionWrapperImplementation : public DifferentiableFunctionWrapperImplementation { using Base = DifferentiableFunctionWrapperImplementation; public: using Base::Base; virtual LocalFunctionInterface wrappedLocalFunction() const { return localFunction(this->get()); } virtual const EntitySet& wrappedEntitySet() const { return this->get().entitySet(); } }; }}} // namespace Dune::Functions::Imp #endif // DUNE_FUNCTIONS_GRIDFUNCTIONS_GRID_FUNCTION_IMP_HH dune-functions-2.5.1/dune/functions/gridfunctions/gridviewentityset.hh000066400000000000000000000035351313314422100264130ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_GRIDFUNCTIONS_GRIDVIEWENTITYSET_HH #define DUNE_FUNCTIONS_GRIDFUNCTIONS_GRIDVIEWENTITYSET_HH #include namespace Dune { namespace Functions { /** * \brief An entity set for all entities of given codim in a grid view * * \ingroup FunctionUtility * * This implements the \ref Concept::EntitySet concept. */ template class GridViewEntitySet { public: typedef GV GridView; enum { codim = cd }; //! Type of Elements contained in this EntitySet typedef typename GridView::template Codim::Entity Element; //! Type of local coordinates with respect to the Element typedef typename Element::Geometry::LocalCoordinate LocalCoordinate; typedef typename Element::Geometry::GlobalCoordinate GlobalCoordinate; typedef Element value_type; //! A forward iterator typedef typename GridView::template Codim::Iterator const_iterator; //! Same as const_iterator typedef const_iterator iterator; /** * \brief Construct GridViewEntitySet for a GridView * */ GridViewEntitySet(const GridView& gv) : gv_(gv) {} //! Returns true if e is contained in the EntitySet bool contains(const Element& e) const { return gv_.contains(e); } //! Number of Elements visited by an iterator size_t size() const { return gv_.size(codim); } //! Create a begin iterator const_iterator begin() const { return gv_.template begin(); } //! Create an end iterator const_iterator end() const { return gv_.template end(); } const GridView& gridView() const { return gv_; } private: GridView gv_; }; } // end of namespace Dune::Functions } // end of namespace Dune #endif // DUNE_FUNCTIONS_GRIDFUNCTIONS_GRIDVIEWENTITYSET_HH dune-functions-2.5.1/dune/functions/gridfunctions/gridviewfunction.hh000066400000000000000000000066521313314422100262130ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_GRIDFUNCTIONS_GRIDVIEWFUNCTION_HH #define DUNE_FUNCTIONS_GRIDFUNCTIONS_GRIDVIEWFUNCTION_HH #include #include #include #include #include namespace Dune { namespace Functions { template class DerivativeTraits=DefaultDerivativeTraits, size_t bufferSize=56> class GridViewFunction {}; /** * \brief Wrapper class for functions defined on a GridView * * \ingroup FunctionInterface * * Being defined on a grid view means in particular that you can evaluate the function * in local coordinates of a given element of the grid view. * * This models the \ref Concept::GridViewFunction concept. * * \tparam GV The GridView that the function is defined on * \tparam Domain The domain type used for function arguments * \tparam Range The range type used for function values */ template class DerivativeTraits, size_t bufferSize> class GridViewFunction : public GridFunction, DerivativeTraits, bufferSize> { using Base = GridFunction, DerivativeTraits, bufferSize>; public: using GridView = GV; using Base::Base; }; /** * \brief Construct a function modeling GridViewFunction from function and grid view * * This spezialization is used for functions that already * support localFunction(). It will simply return a copy of f. * * \param f A function object supporting argument compatible with global coordinates * \param gridView The GridView the function should act on. * * \returns A function that models the GridViewFunction interface. */ template() , int>::type = 0> typename std::decay::type makeGridViewFunction(F&& f, const GridView& gridView) { return std::forward(f); } /** * \brief Construct a function modeling GridViewFunction from function and grid view * * This spezialization is used for functions that do not * support localFunction() themselves. It will forward * to makeAnalyticGridViewFunction. * Notice that the returned function will store a copy of * the original function and a pointer to the GridView. * It can only be used as long as the latter exists. * Hence you must take care to store the GridView yourself. * \todo Should we store a copy of the GridView? * * \param f A function object supporting argument compatible with global coordinates * \param gridView The GridView the function should act on. * * \returns A function that models the GridFunction interface. */ template()) , int>::type = 0> auto makeGridViewFunction(F&& f, const GridView& gridView) -> decltype(makeAnalyticGridViewFunction(std::forward(f), gridView)) { return makeAnalyticGridViewFunction(std::forward(f), gridView); } } // end of namespace Dune::Functions } // end of namespace Dune #endif // DUNE_FUNCTIONS_GRIDFUNCTIONS_GRIDVIEWFUNCTION_HH dune-functions-2.5.1/dune/functions/gridfunctions/localderivativetraits.hh000066400000000000000000000023601313314422100272210ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_GRIDFUNCTIONS_LOCALDERIVATIVE_TRAITS_HH #define DUNE_FUNCTIONS_GRIDFUNCTIONS_LOCALDERIVATIVE_TRAITS_HH #include namespace Dune { namespace Functions { /** * \brief Derivative traits for local functions * * \ingroup FunctionUtility * * This provides derivative traits to be used by local functions with * given EntitySet and global DerivativeTraits. * * The reason why this is needed is that local functions return * derivatives wrt to global coordinates although the arguments * for these derivatives are local coordinates. */ template class DerivativeTraits=DefaultDerivativeTraits> struct LocalDerivativeTraits { using LocalDomain = typename EntitySet::LocalCoordinate; using Domain = typename EntitySet::GlobalCoordinate; template struct Traits { typedef InvalidRange Range; }; template struct Traits { using Range = typename DerivativeTraits::Range; }; }; }} // namespace Dune::Functions #endif // DUNE_FUNCTIONS_GRIDFUNCTIONS_LOCALDERIVATIVE_TRAITS_HH dune-functions-2.5.1/dune/functions/gridfunctions/test/000077500000000000000000000000001313314422100232525ustar00rootroot00000000000000dune-functions-2.5.1/dune/functions/gridfunctions/test/.gitignore000066400000000000000000000001651313314422100252440ustar00rootroot00000000000000# temporary files generated by the test system *.log *.trs # individual tests discretescalarglobalbasisfunctiontest dune-functions-2.5.1/dune/functions/gridfunctions/test/CMakeLists.txt000066400000000000000000000003161313314422100260120ustar00rootroot00000000000000# tests that should build and run successfully dune_add_test(SOURCES analyticgridviewfunctiontest.cc) dune_add_test(SOURCES discreteglobalbasisfunctiontest.cc) dune_add_test(SOURCES gridfunctiontest.cc) dune-functions-2.5.1/dune/functions/gridfunctions/test/analyticgridviewfunctiontest.cc000066400000000000000000000055761313314422100316110ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include using namespace Dune; using namespace Dune::Functions; using namespace Dune::Functions::Test; double x_component_A(const Dune::FieldVector & x) { return x[0]; } template double x_component_B(const Coord & x) { return x[0]; } int main (int argc, char* argv[]) try { Dune::MPIHelper::instance(argc, argv); // Generate grid for testing const int dim = 2; typedef YaspGrid GridType; FieldVector l(1); std::array elements = {{10, 10}}; GridType grid(l,elements); using GridView = typename GridType::LeafGridView; const GridView& gridView = grid.leafGridView(); double exactIntegral = 0.5; bool passed = true; using Domain = GridView::Codim<0>::Geometry::GlobalCoordinate; std::cout << "Testing manual construction of AnalyticGridViewFunction with range type double" << std::endl; { using Range = double; auto f = [](const Domain& x) {return x[0];}; AnalyticGridViewFunction fGVF(f, gridView); passed = passed and Dune::Functions::Test::checkGridViewFunction(gridView, fGVF, exactIntegral); } std::cout << "Testing makeAnalyticGridViewFunction with range type double" << std::endl; { auto f = [](const Domain& x) {return x[0];}; passed = passed and Dune::Functions::Test::checkGridViewFunction(gridView, makeAnalyticGridViewFunction(f, gridView), exactIntegral); } std::cout << "Testing makeGridViewFunction with range type double" << std::endl; { auto f = [](const Domain& x) {return x[0];}; passed = passed and Dune::Functions::Test::checkGridViewFunction(gridView, makeGridViewFunction(f, gridView), exactIntegral); } std::cout << "Testing makeAnalyticGridViewFunction with free function" << std::endl; { auto f = x_component_A; passed = passed and Dune::Functions::Test::checkGridViewFunction(gridView, makeAnalyticGridViewFunction(f, gridView), exactIntegral); } std::cout << "Testing makeAnalyticGridViewFunction with free template function" << std::endl; { auto f = x_component_B; passed = passed and Dune::Functions::Test::checkGridViewFunction(gridView, makeAnalyticGridViewFunction(f, gridView), exactIntegral); } if (passed) std::cout << "All tests passed" << std::endl; return passed ? 0: 1; } catch ( Dune::Exception &e ) { std::cerr << "Dune reported error: " << e << std::endl; return 1; } catch(...) { std::cerr << "Unknown exception thrown!" << std::endl; return 1; } dune-functions-2.5.1/dune/functions/gridfunctions/test/discreteglobalbasisfunctiontest.cc000066400000000000000000000067221313314422100322430ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include #include #include #include using namespace Dune; using namespace Dune::Functions; using namespace Dune::Functions::Test; template bool checkInterpolationConsistency(B&& basis, C&& x) { using Coeff = typename std::decay::type; using Range = typename Coeff::value_type; // generate a discrete function auto f = Dune::Functions::makeDiscreteGlobalBasisFunction (basis, Dune::TypeTree::hybridTreePath(), x); Coeff y; interpolate(basis, y, f); for (typename std::decay_t::size_type i=0; i 1e-10) { std::cout << "Interpolation of DiscreteGlobalBasisFunction differs from original coefficient vector" << std::endl; return false; } } return true; } int main (int argc, char* argv[]) try { Dune::MPIHelper::instance(argc, argv); bool passed = true; // Generate grid for testing const int dim = 2; typedef YaspGrid GridType; FieldVector l(1); std::array elements = {{10, 10}}; GridType grid(l,elements); // Test whether PQ1FunctionSpaceBasis.hh can be instantiated on the leaf view typedef GridType::LeafGridView GridView; // typedef PQ1NodalBasis Basis; typedef PQkNodalBasis Basis; const GridView& gridView = grid.leafGridView(); Basis feBasis(gridView); using Domain = GridView::template Codim<0>::Geometry::GlobalCoordinate; { using Range = FieldVector; auto f = [](const Domain& x){ Range y; for (typename Range::size_type i=0; i x; interpolate(feBasis, x, f); passed = passed and checkInterpolationConsistency(feBasis, x); } // Sample the function f(x,y) = x on the grid vertices // If we use that as the coefficients of a finite element function, // we know its integral and can check whether quadrature returns // the correct result. Notice that resizing is done by the interpolate method. std::vector > x; auto fAnalytic = [](const Domain& x){ return x[0];}; interpolate(feBasis, x, fAnalytic); passed = passed and checkInterpolationConsistency(feBasis, x); // generate a discrete function to evaluate the integral auto f = Dune::Functions::makeDiscreteGlobalBasisFunction (feBasis, Dune::TypeTree::hybridTreePath(), x); double exactIntegral = 0.5; std::cout << "Testing with raw DiscreteGlobalBasisFunction" << std::endl; passed = passed and Dune::Functions::Test::checkGridViewFunction(gridView, f, exactIntegral); if (passed) std::cout << "All tests passed" << std::endl; return passed ? 0: 1; } catch ( Dune::Exception &e ) { std::cerr << "Dune reported error: " << e << std::endl; return 1; } catch(...) { std::cerr << "Unknown exception thrown!" << std::endl; return 1; } dune-functions-2.5.1/dune/functions/gridfunctions/test/gridfunctiontest.cc000066400000000000000000000027451313314422100271640ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include //#include //#include #include #include #include #include #include #include #include using namespace Dune; using namespace Dune::Functions; int main (int argc, char* argv[]) try { Dune::MPIHelper::instance(argc, argv); // Generate grid for testing const int dim = 2; typedef YaspGrid GridType; FieldVector l(1); // FieldVector l = {{21.0, 4.0}}; std::array elements = {{10, 10}}; GridType grid(l,elements); // Test whether PQ1FunctionSpaceBasis.hh can be instantiated on the leaf view using GridView = GridType::LeafGridView; using EntitySet = GridViewEntitySet; auto entitySet = EntitySet(grid.leafGridView()); auto p = Polynomial({0, 1, 2}); GridFunction f; return 0; } catch ( Dune::Exception &e ) { std::cerr << "Dune reported error: " << e << std::endl; return 1; } catch(...) { std::cerr << "Unknown exception thrown!" << std::endl; return 1; } dune-functions-2.5.1/dune/functions/gridfunctions/test/gridfunctiontest.hh000066400000000000000000000121711313314422100271700ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTIONS_GRIDFUNCTIONS_TEST_GRIDFUNCTIONTEST_HH #define DUNE_FUNCTIONS_GRIDFUNCTIONS_TEST_GRIDFUNCTIONTEST_HH #include #include #include #include #include namespace Dune { namespace Functions { namespace Test { bool checkTrue(bool value, std::string error) { if (not(value)) std::cout << "TEST FAILURE:" << error << std::endl; return value; } template double integrateGridViewFunction(const GridView& gridView, const F& f, unsigned int quadOrder) { static const int dim = GridView::dimension; double integral = 0; auto fLocal = localFunction(f); // Loop over elements and integrate over the function for (const auto& e : elements(gridView)) { auto geometry = e.geometry(); fLocal.bind(e); // A quadrature rule const auto& quad = QuadratureRules::rule(e.type(), quadOrder); // Loop over all quadrature points for ( size_t pt=0; pt < quad.size(); pt++ ) { // Position of the current quadrature point in the reference element auto quadPos = quad[pt].position(); // The multiplicative factor in the integral transformation formula auto integrationElement = geometry.integrationElement(quadPos); integral += fLocal(quadPos) * quad[pt].weight() * integrationElement; } fLocal.unbind(); } return integral; } template bool checkGridViewFunction(const GridView& gridView, const F& f, double exactIntegral, unsigned int quadOrder=1) { bool passed = true; double integral; using Dune::Functions::Concept::isGridFunction; using EntitySet = typename F::EntitySet; using Domain = typename EntitySet::GlobalCoordinate; using Range = typename std::result_of::type; std::cout << "Checking raw function f on grid view" << std::endl; passed = checkTrue(isGridFunction(), "Function does not model GridFunction concept"); integral = integrateGridViewFunction(gridView, f, quadOrder); passed = checkTrue(std::abs(integral-exactIntegral) < 1e-10, "Integral is "+std::to_string(integral)+" but should be "+std::to_string(exactIntegral)); std::cout << "Checking GridFunction(f) on grid view" << std::endl; GridFunction f2 = f; passed = checkTrue(isGridFunction(), "Function does not model GridFunction concept"); integral = integrateGridViewFunction(gridView, f2, quadOrder); passed = checkTrue(std::abs(integral-exactIntegral) < 1e-10, "Integral is "+std::to_string(integral)+" but should be "+std::to_string(exactIntegral)); std::cout << "Checking GridViewFunction(f) on grid view" << std::endl; GridViewFunction f3 = f; passed = checkTrue(isGridFunction(), "Function does not model GridFunction concept"); integral = integrateGridViewFunction(gridView, f3, quadOrder); passed = checkTrue(std::abs(integral-exactIntegral) < 1e-10, "Integral is "+std::to_string(integral)+" but should be "+std::to_string(exactIntegral)); std::cout << "Checking makeGridFunction(f) on grid view" << std::endl; auto f4 = makeGridViewFunction(f, gridView); passed = checkTrue(isGridFunction(), "Function does not model GridFunction concept"); integral = integrateGridViewFunction(gridView, f4, quadOrder); passed = checkTrue(std::abs(integral-exactIntegral) < 1e-10, "Integral is "+std::to_string(integral)+" but should be "+std::to_string(exactIntegral)); std::cout << "Checking GridViewFunction(makeGridFunction(f)) on grid view" << std::endl; GridViewFunction f5 = f4; integral = integrateGridViewFunction(gridView, f5, quadOrder); passed = checkTrue(std::abs(integral-exactIntegral) < 1e-10, "Integral is "+std::to_string(integral)+" but should be "+std::to_string(exactIntegral)); std::cout << "Checking default constructed and assigned GridViewFunction on grid view" << std::endl; GridViewFunction f6; f6 = f5; integral = integrateGridViewFunction(gridView, f6, quadOrder); passed = checkTrue(std::abs(integral-exactIntegral) < 1e-10, "Integral is "+std::to_string(integral)+" but should be "+std::to_string(exactIntegral)); std::cout << "Checking reassigned GridViewFunction on grid view" << std::endl; f6 = f3; integral = integrateGridViewFunction(gridView, f6, quadOrder); passed = checkTrue(std::abs(integral-exactIntegral) < 1e-10, "Integral is "+std::to_string(integral)+" but should be "+std::to_string(exactIntegral)); return passed; } } // namespace Test } // namespace Functions } // namespace Dune #endif // DUNE_FUNCTIONS_GRIDFUNCTIONS_TEST_GRIDFUNCTIONTEST_HH dune-functions-2.5.1/dune/functions/modules.md000066400000000000000000000032221313314422100214060ustar00rootroot00000000000000 # Modules @defgroup Functions Functions @brief Interfaces and implementations of functions Since interfaces in dune-functions rely on duck-typing there are no base classes to ensure interfaces. Instead of this each type can be checked, if it satisfies a certain concept as defined in the Dune::Functions::Concept namespace. Additionally there is a polymorphic interface consisting of type-erasure wrappers in the spirit of std::function. @defgroup FunctionConcepts Function concepts @ingroup Functions @brief Concept definitions for function interfaces @defgroup FunctionInterface Function interface wrappers @ingroup Functions @brief Type-erasure based polymorphic wrappers @defgroup FunctionImplementations Function implementations @ingroup Functions @brief Concrete function implementations @defgroup FunctionUtility Function related utilities @ingroup Functions @brief Helper classes and functions related to functions @defgroup FunctionSpaceBases Function space bases @brief Interfaces and implementation of global bases for grid function space @defgroup FunctionSpaceBasesConcepts Function space basis concepts @ingroup FunctionSpaceBases @defgroup FunctionSpaceBasesImplementations Function space basis implementations @ingroup FunctionSpaceBases @brief Implementations of the GlobalBasis concept @defgroup FunctionSpaceBasesUtilities Function space basis related utilities @ingroup FunctionSpaceBases @defgroup Utility Utility @brief Various helper classes and functions @defgroup TypeErasure Utilities for type-erasure @brief Helper classes for implementing type-erased interfaces @ingroup Utility dune-functions-2.5.1/examples/000077500000000000000000000000001313314422100162705ustar00rootroot00000000000000dune-functions-2.5.1/examples/CMakeLists.txt000066400000000000000000000005171313314422100210330ustar00rootroot00000000000000add_executable("advection-reaction-dg" advection-reaction-dg.cc) target_link_dune_default_libraries("advection-reaction-dg") add_executable("poisson-pq2" poisson-pq2.cc) target_link_dune_default_libraries("poisson-pq2") add_executable("stokes-taylorhood" stokes-taylorhood.cc) target_link_dune_default_libraries("stokes-taylorhood") dune-functions-2.5.1/examples/advection-reaction-dg.cc000066400000000000000000000450741313314422100227570ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** \file * \brief Example implementation of a DG-discretized advection-reaction equation * * Implemented using Alexandre Ern's lecture notes "Discontinuous Galerkin Methods", Chapter 3.3. */ using namespace Dune; // Compute the element stiffness matrix for an element coupling with itself template void getLocalMatrix(const LocalView& localView, MatrixType& elementMatrix, LocalVelocityField&& localVelocityField, LocalReactionCoefficient&& localReactionCoefficient) { // Get the grid element from the local FE basis view typedef typename LocalView::Element Element; const Element& element = localView.element(); const int dim = Element::dimension; auto geometry = element.geometry(); // Get set of shape functions for this element const auto& localFiniteElement = localView.tree().finiteElement(); // Set all matrix entries to zero elementMatrix.setSize(localFiniteElement.size(),localFiniteElement.size()); elementMatrix = 0; // fills the entire matrix with zeroes // Get a quadrature rule int order = 2*dim*localFiniteElement.localBasis().order(); const auto& quad = QuadratureRules::rule(element.type(), order); // Loop over all quadrature points for (const auto& quadPoint : quad) { // The transposed inverse Jacobian of the map from the reference element to the element const auto& jacobian = geometry.jacobianInverseTransposed(quadPoint.position()); // The multiplicative factor in the integral transformation formula const double integrationElement = geometry.integrationElement(quadPoint.position()); // The values of the shape functions at the quadrature point std::vector > values; localFiniteElement.localBasis().evaluateFunction(quadPoint.position(), values); // The gradients of the shape functions on the reference element std::vector > referenceGradients; localFiniteElement.localBasis().evaluateJacobian(quadPoint.position(), referenceGradients); // Compute the shape function gradients on the real element std::vector > gradients(referenceGradients.size()); for (size_t i=0; i::rule(intersection.type(), order); for (auto&& quadPoint : quad) { auto positionInElement = intersection.geometryInInside().global(quadPoint.position()); // The values of the shape functions at the quadrature point std::vector > values; localFiniteElement.localBasis().evaluateFunction(positionInElement, values); auto factor = localVelocityField(positionInElement)*intersection.integrationOuterNormal(quadPoint.position()); // Disable the term at outflow boundary faces if (!intersection.neighbor()) factor = std::min(factor, 0.0); for (size_t i=0; i void getOffDiagonalLocalMatrix(const Intersection& intersection, const LocalView& insideLocalView, const LocalView& outsideLocalView, MatrixType& elementMatrix, LocalVelocityField&& localVelocityField) { const int intersectionDim = Intersection::mydimension; // Get set of shape functions for the inside and the outside element const auto& insideLocalFiniteElement = insideLocalView.tree().finiteElement(); const auto& outsideLocalFiniteElement = outsideLocalView.tree().finiteElement(); // Set all matrix entries to zero elementMatrix.setSize(insideLocalFiniteElement.size(),outsideLocalFiniteElement.size()); elementMatrix = 0; // fills the entire matrix with zeroes // Get a quadrature rule on the element face int order = insideLocalFiniteElement.localBasis().order() * outsideLocalFiniteElement.localBasis().order(); const auto& quad = QuadratureRules::rule(intersection.type(), order); for (auto&& quadPoint : quad) { auto positionInInsideElement = intersection.geometryInInside().global(quadPoint.position()); auto positionInOutsideElement = intersection.geometryInOutside().global(quadPoint.position()); // The values of the shape functions at the quadrature point std::vector > insideValues, outsideValues; insideLocalFiniteElement. localBasis().evaluateFunction(positionInInsideElement, insideValues); outsideLocalFiniteElement.localBasis().evaluateFunction(positionInOutsideElement, outsideValues); // Velocity field times face normal auto factor = localVelocityField(positionInInsideElement)*intersection.integrationOuterNormal(quadPoint.position()); for (size_t i=0; i void getVolumeTerm( const LocalView& localView, BlockVector >& localRhs, LocalSourceTerm&& localSourceTerm) { // Get the grid element from the local FE basis view typedef typename LocalView::Element Element; const Element& element = localView.element(); const int dim = Element::dimension; // Get set of shape functions for this element const auto& localFiniteElement = localView.tree().finiteElement(); // Set all entries to zero localRhs.resize(localFiniteElement.size()); localRhs = 0; // A quadrature rule int order = dim*localFiniteElement.localBasis().order(); const auto& quad = QuadratureRules::rule(element.type(), order); // Loop over all quadrature points for (const auto& quadPoint : quad) { // The multiplicative factor in the integral transformation formula const double integrationElement = element.geometry().integrationElement(quadPoint.position()); double functionValue = localSourceTerm(quadPoint.position()); // Evaluate all shape function values at this point std::vector > shapeFunctionValues; localFiniteElement.localBasis().evaluateFunction(quadPoint.position(), shapeFunctionValues); // Actually compute the vector entries for (size_t i=0; i void getOccupationPattern(const FEBasis& feBasis, MatrixIndexSet& nb) { // Total number of grid vertices auto n = feBasis.size(); nb.resize(n, n); // A view on the FE basis on a single element auto localView = feBasis.localView(); auto localIndexSet = feBasis.localIndexSet(); // Loop over all leaf elements for(const auto& e : elements(feBasis.gridView())) { // Bind the local FE basis view to the current element localView.bind(e); localIndexSet.bind(localView); for (size_t i=0; i void assembleStiffnessMatrix(const FEBasis& feBasis, BCRSMatrix >& matrix, BlockVector >& rhs, VelocityField&& velocityField, ReactionCoefficient&& reactionCoefficient, SourceTerm&& sourceTerm) { // Get the grid view from the finite element basis typedef typename FEBasis::GridView GridView; GridView gridView = feBasis.gridView(); // Make 'local' versions of the coefficient functions // 'local' means that you can bind them to grid elements, and evaluate them // in local coordinates of that element. auto localVelocityField = localFunction(Functions::makeGridViewFunction(velocityField, gridView)); auto localReactionCoefficient = localFunction(Functions::makeGridViewFunction(reactionCoefficient, gridView)); auto localSourceTerm = localFunction(Functions::makeGridViewFunction(sourceTerm, gridView)); // MatrixIndexSets store the occupation pattern of a sparse matrix. // They are not particularly efficient, but simple to use. MatrixIndexSet occupationPattern; getOccupationPattern(feBasis, occupationPattern); // ... and give it the occupation pattern we want. occupationPattern.exportIdx(matrix); // set rhs to correct length -- the total number of basis vectors in the basis rhs.resize(feBasis.size()); // Set all entries to zero matrix = 0; rhs = 0; // A view on the FE basis on a single element auto localView = feBasis.localView(); auto localIndexSet = feBasis.localIndexSet(); // A loop over all elements of the grid for(const auto& element : elements(gridView)) { // Bind the local FE basis view to the current element localView.bind(element); localIndexSet.bind(localView); localVelocityField.bind(element); localReactionCoefficient.bind(element); // Now let's get the element stiffness matrix // A dense matrix is used for the element stiffness matrix Matrix > elementMatrix; getLocalMatrix(localView, elementMatrix, localVelocityField, localReactionCoefficient); // Add element stiffness matrix onto the global stiffness matrix for (size_t i=0; i > localRhs; localSourceTerm.bind(element); getVolumeTerm(localView, localRhs, localSourceTerm); for (size_t i=0; i GridType; FieldVector l = {1.0, 1.0}; std::array elements = {10, 10}; GridType grid(l,elements); typedef GridType::LeafGridView GridView; GridView gridView = grid.leafGridView(); ///////////////////////////////////////////////////////// // Choose a finite element space ///////////////////////////////////////////////////////// // Second-order Lagrange DG space typedef Functions::LagrangeDGBasis FEBasis; FEBasis feBasis(gridView); ///////////////////////////////////////////////////////// // Stiffness matrix and right hand side vector ///////////////////////////////////////////////////////// typedef BlockVector > VectorType; typedef BCRSMatrix > MatrixType; VectorType rhs; MatrixType stiffnessMatrix; ///////////////////////////////////////////////////////// // Assemble the system ///////////////////////////////////////////////////////// using Domain = GridType::Codim<0>::Geometry::GlobalCoordinate; // FieldVector auto sourceTerm = [] (const Domain& x) { return 10;}; auto velocityField = [] (const Domain& x) -> Domain { return {1,1};}; auto reactionCoefficient = [] (const Domain& x) { return 10;}; assembleStiffnessMatrix(feBasis, stiffnessMatrix, rhs, velocityField, reactionCoefficient, sourceTerm); ///////////////////////////////////////////////// // Choose an initial iterate ///////////////////////////////////////////////// VectorType x(feBasis.size()); x = 0; //////////////////////////// // Compute solution //////////////////////////// // Technicality: turn the matrix into a linear operator MatrixAdapter op(stiffnessMatrix); // Sequential incomplete LU decomposition as the preconditioner SeqILU0 preconditioner(stiffnessMatrix,1.0); // Richardson preconditioner(1.0); // Preconditioned conjugate-gradient solver RestartedGMResSolver solver(op, preconditioner, 1e-10, // desired residual reduction factor 500, // number of iterations between restarts 500, // maximum number of iterations 2); // verbosity of the solver // Object storing some statistics about the solving process InverseOperatorResult statistics; // Solve! solver.apply(x, rhs, statistics); //////////////////////////////////////////////////////////////////////////// // Make a discrete function from the FE basis and the coefficient vector //////////////////////////////////////////////////////////////////////////// auto xFunction = Dune::Functions::makeDiscreteGlobalBasisFunction(feBasis, Dune::TypeTree::hybridTreePath(), x); ////////////////////////////////////////////////////////////////////////////////////////////// // Write result to VTK file // We need to subsample, because VTK cannot natively display real second-order functions ////////////////////////////////////////////////////////////////////////////////////////////// SubsamplingVTKWriter vtkWriter(gridView,2); vtkWriter.addVertexData(xFunction, VTK::FieldInfo("x", VTK::FieldInfo::Type::scalar, 1)); vtkWriter.write("advection-reaction-dg"); } // Error handling catch (Exception e) { std::cout << e << std::endl; } dune-functions-2.5.1/examples/poisson-pq2.cc000066400000000000000000000324501313314422100207750ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Dune; // Compute the stiffness matrix for a single element template void getLocalMatrix( const LocalView& localView, MatrixType& elementMatrix) { // Get the grid element from the local FE basis view typedef typename LocalView::Element Element; const Element& element = localView.element(); const int dim = Element::dimension; auto geometry = element.geometry(); // Get set of shape functions for this element const auto& localFiniteElement = localView.tree().finiteElement(); // Set all matrix entries to zero elementMatrix.setSize(localFiniteElement.localBasis().size(),localFiniteElement.localBasis().size()); elementMatrix = 0; // fills the entire matrix with zeroes // Get a quadrature rule int order = 2*(dim*localFiniteElement.localBasis().order()-1); const QuadratureRule& quad = QuadratureRules::rule(element.type(), order); // Loop over all quadrature points for (size_t pt=0; pt < quad.size(); pt++) { // Position of the current quadrature point in the reference element const FieldVector& quadPos = quad[pt].position(); // The transposed inverse Jacobian of the map from the reference element to the element const auto& jacobian = geometry.jacobianInverseTransposed(quadPos); // The multiplicative factor in the integral transformation formula const double integrationElement = geometry.integrationElement(quadPos); // The gradients of the shape functions on the reference element std::vector > referenceGradients; localFiniteElement.localBasis().evaluateJacobian(quadPos, referenceGradients); // Compute the shape function gradients on the real element std::vector > gradients(referenceGradients.size()); for (size_t i=0; i void getVolumeTerm( const LocalView& localView, BlockVector >& localRhs, LocalVolumeTerm&& localVolumeTerm) { // Get the grid element from the local FE basis view typedef typename LocalView::Element Element; const Element& element = localView.element(); const int dim = Element::dimension; // Get set of shape functions for this element const auto& localFiniteElement = localView.tree().finiteElement(); // Set all entries to zero localRhs.resize(localFiniteElement.localBasis().size()); localRhs = 0; // A quadrature rule int order = dim*localFiniteElement.localBasis().order(); const QuadratureRule& quad = QuadratureRules::rule(element.type(), order); // Loop over all quadrature points for ( size_t pt=0; pt < quad.size(); pt++ ) { // Position of the current quadrature point in the reference element const FieldVector& quadPos = quad[pt].position(); // The multiplicative factor in the integral transformation formula const double integrationElement = element.geometry().integrationElement(quadPos); double functionValue = localVolumeTerm(quadPos); // Evaluate all shape function values at this point std::vector > shapeFunctionValues; localFiniteElement.localBasis().evaluateFunction(quadPos, shapeFunctionValues); // Actually compute the vector entries for (size_t i=0; i void getOccupationPattern(const FEBasis& feBasis, MatrixIndexSet& nb) { // Total number of grid vertices auto n = feBasis.size(); nb.resize(n, n); // A view on the FE basis on a single element typename FEBasis::LocalView localView(feBasis); auto localIndexSet = feBasis.localIndexSet(); // Loop over all leaf elements for(const auto& e : elements(feBasis.gridView())) { // Bind the local FE basis view to the current element localView.bind(e); localIndexSet.bind(localView); // There is a matrix entry a_ij if the i-th and j-th vertex are connected in the grid for (size_t i=0; i void assembleLaplaceMatrix(const FEBasis& feBasis, BCRSMatrix >& matrix, BlockVector >& rhs, VolumeTerm&& volumeTerm) { // Get the grid view from the finite element basis typedef typename FEBasis::GridView GridView; GridView gridView = feBasis.gridView(); auto localVolumeTerm = localFunction(Functions::makeGridViewFunction(volumeTerm, gridView)); // MatrixIndexSets store the occupation pattern of a sparse matrix. // They are not particularly efficient, but simple to use. MatrixIndexSet occupationPattern; getOccupationPattern(feBasis, occupationPattern); // ... and give it the occupation pattern we want. occupationPattern.exportIdx(matrix); // set rhs to correct length -- the total number of basis vectors in the basis rhs.resize(feBasis.size()); // Set all entries to zero matrix = 0; rhs = 0; // A view on the FE basis on a single element auto localView = feBasis.localView(); auto localIndexSet = feBasis.localIndexSet(); // A loop over all elements of the grid for(const auto& e : elements(gridView)) { // Bind the local FE basis view to the current element localView.bind(e); localIndexSet.bind(localView); // Now let's get the element stiffness matrix // A dense matrix is used for the element stiffness matrix Matrix > elementMatrix; getLocalMatrix(localView, elementMatrix); // Add element stiffness matrix onto the global stiffness matrix for (size_t i=0; i > localRhs; localVolumeTerm.bind(e); getVolumeTerm(localView, localRhs, localVolumeTerm); for (size_t i=0; i is currently not supported, // we use a vector which, in contrast to vector // is a real container. template void boundaryTreatment (const FEBasis& feBasis, const FieldVector& bbox, std::vector& dirichletNodes ) { using Coordinate = typename FEBasis::GridView::template Codim<0>::Geometry::GlobalCoordinate; // Interpolating the indicator function of the boundary will // mark all boundary dofs. interpolate(feBasis, Dune::TypeTree::hybridTreePath(), dirichletNodes, [&bbox](Coordinate x){ bool isBoundary = false; for (std::size_t j=0; j bbox[j]-1e-8; return isBoundary; }); } int main (int argc, char *argv[]) try { // Set up MPI, if available MPIHelper::instance(argc, argv); /////////////////////////////////// // Generate the grid /////////////////////////////////// const int dim = 2; typedef YaspGrid GridType; FieldVector l(1); std::array elements = {10, 10}; GridType grid(l,elements); typedef GridType::LeafGridView GridView; GridView gridView = grid.leafGridView(); ///////////////////////////////////////////////////////// // Choose a finite element space ///////////////////////////////////////////////////////// typedef Functions::PQkNodalBasis FEBasis; FEBasis feBasis(gridView); ///////////////////////////////////////////////////////// // Stiffness matrix and right hand side vector ///////////////////////////////////////////////////////// typedef BlockVector > VectorType; typedef BCRSMatrix > MatrixType; VectorType rhs; MatrixType stiffnessMatrix; ///////////////////////////////////////////////////////// // Assemble the system ///////////////////////////////////////////////////////// using Domain = GridType::template Codim<0>::Geometry::GlobalCoordinate; auto rightHandSide = [] (const Domain& x) { return 10;}; assembleLaplaceMatrix(feBasis, stiffnessMatrix, rhs, rightHandSide); ///////////////////////////////////////////////// // Choose an initial iterate ///////////////////////////////////////////////// VectorType x(feBasis.size()); x = 0; // Determine Dirichlet dofs std::vector dirichletNodes; boundaryTreatment(feBasis, l, dirichletNodes); // Don't trust on non-standard M_PI. auto pi = std::acos(-1.0); auto dirichletValueFunction = [pi](FieldVector x){ return std::sin(2*pi*x[0]); }; // Interpolate dirichlet values at the boundary nodes interpolate(feBasis, Dune::TypeTree::hybridTreePath(), rhs, dirichletValueFunction, dirichletNodes); //////////////////////////////////////////// // Modify Dirichlet rows //////////////////////////////////////////// // loop over the matrix rows for (size_t i=0; i op(stiffnessMatrix); // Sequential incomplete LU decomposition as the preconditioner SeqILU0 ilu0(stiffnessMatrix,1.0); // Preconditioned conjugate-gradient solver CGSolver cg(op, ilu0, // preconditioner 1e-4, // desired residual reduction factor 50, // maximum number of iterations 2); // verbosity of the solver // Object storing some statistics about the solving process InverseOperatorResult statistics; // Solve! cg.apply(x, rhs, statistics); //////////////////////////////////////////////////////////////////////////// // Make a discrete function from the FE basis and the coefficient vector //////////////////////////////////////////////////////////////////////////// auto xFunction = Dune::Functions::makeDiscreteGlobalBasisFunction(feBasis, Dune::TypeTree::hybridTreePath(), x); ////////////////////////////////////////////////////////////////////////////////////////////// // Write result to VTK file // We need to subsample, because VTK cannot natively display real second-order functions ////////////////////////////////////////////////////////////////////////////////////////////// SubsamplingVTKWriter vtkWriter(gridView,2); vtkWriter.addVertexData(xFunction, VTK::FieldInfo("x", VTK::FieldInfo::Type::scalar, 1)); vtkWriter.write("poisson-pq2"); } // Error handling catch (Exception e) { std::cout << e << std::endl; } dune-functions-2.5.1/examples/stokes-taylorhood.cc000066400000000000000000000414471313314422100223030ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // { using_namespace_dune_begin } using namespace Dune; // { using_namespace_dune_end } // Compute the stiffness matrix for a single element // { local_assembler_signature_begin } template void getLocalMatrix(const LocalView& localView, Matrix >& elementMatrix) // { local_assembler_signature_end } { // Get the grid element from the local FE basis view // { local_assembler_get_element_information_begin } typedef typename LocalView::Element Element; const Element& element = localView.element(); const int dim = Element::dimension; auto geometry = element.geometry(); // { local_assembler_get_element_information_end } // Set all matrix entries to zero // { initialize_element_matrix_begin } elementMatrix.setSize(localView.size(), localView.size()); elementMatrix = 0; // fills the entire matrix with zeroes // { initialize_element_matrix_end } // Get set of shape functions for this element // { get_local_fe_begin } using namespace Dune::TypeTree::Indices; const auto& velocityLocalFiniteElement = localView.tree().child(_0,0).finiteElement(); /*@\label{li:stokes_taylorhood_get_velocity_lfe}@*/ const auto& pressureLocalFiniteElement = localView.tree().child(_1).finiteElement(); /*@\label{li:stokes_taylorhood_get_pressure_lfe}@*/ // { get_local_fe_end } // Get a quadrature rule // { begin_quad_loop_begin } int order = 2*(dim*velocityLocalFiniteElement.localBasis().order()-1); const auto& quad = QuadratureRules::rule(element.type(), order); // Loop over all quadrature points for (const auto& quadPoint : quad) { // { begin_quad_loop_end } // { quad_loop_preamble_begin } // The transposed inverse Jacobian of the map from the reference element to the element const auto jacobian = geometry.jacobianInverseTransposed(quadPoint.position()); // The multiplicative factor in the integral transformation formula const double integrationElement = geometry.integrationElement(quadPoint.position()); // { quad_loop_preamble_end } /////////////////////////////////////////////////////////////////////// // Velocity--velocity coupling /////////////////////////////////////////////////////////////////////// // The gradients of the shape functions on the reference element // { velocity_gradients_begin } std::vector > referenceGradients; velocityLocalFiniteElement.localBasis().evaluateJacobian(quadPoint.position(), referenceGradients); // Compute the shape function gradients on the grid element std::vector > gradients(referenceGradients.size()); for (size_t i=0; i > pressureValues; pressureLocalFiniteElement.localBasis().evaluateFunction(quadPoint.position(), pressureValues); // { pressure_values_end } // Compute the actual matrix entries // { velocity_pressure_coupling_begin } for (size_t i=0; i void getOccupationPattern(const Basis& basis, std::array,2>& nb) { enum {dim = Basis::GridView::dimension}; // Set sizes of the 2x2 submatrices for (size_t i=0; i<2; i++) for (size_t j=0; j<2; j++) nb[i][j].resize(basis.size({i}), basis.size({j})); // A view on the FE basis on a single element auto localView = basis.localView(); auto localIndexSet = basis.localIndexSet(); // Loop over all leaf elements for(const auto& e : elements(basis.gridView())) { // Bind the local FE basis view to the current element localView.bind(e); localIndexSet.bind(localView); // Add element stiffness matrix onto the global stiffness matrix for (size_t i=0; i void assembleStokesMatrix(const Basis& basis, Matrix > >& matrix) // { global_assembler_signature_end } { // MatrixIndexSets store the occupation pattern of a sparse matrix. // They are not particularly efficient, but simple to use. // { setup_matrix_pattern_begin } array, 2> occupationPattern; getOccupationPattern(basis, occupationPattern); // ... and give it the occupation pattern we want. matrix.setSize(2,2); for (int i=0; i<2; i++) for (int j=0; j<2; j++) occupationPattern[i][j].exportIdx(matrix[i][j]); /*@\label{li:stokes_taylorhood_setup_matrix_patterns}@*/ // Set all entries to zero matrix = 0; /*@\label{li:stokes_taylorhood_set_matrix_to_zero}@*/ // { setup_matrix_pattern_end } // A view on the FE basis on a single element // { get_localview_begin } auto localView = basis.localView(); auto localIndexSet = basis.localIndexSet(); // { get_localview_end } // A loop over all elements of the grid // { element_loop_and_bind_begin } for (const auto& element : elements(basis.gridView())) { // Bind the local FE basis view to the current element localView.bind(element); localIndexSet.bind(localView); // { element_loop_and_bind_end } // Now let's get the element stiffness matrix // A dense matrix is used for the element stiffness matrix // { setup_element_stiffness_begin } Matrix > elementMatrix; /*@\label{li:stokes_taylorhood_select_element_matrix_type}@*/ getLocalMatrix(localView, elementMatrix); // { setup_element_stiffness_end } // Add element stiffness matrix onto the global stiffness matrix // { accumulate_global_matrix_begin } for (size_t i=0; i GridType; FieldVector bbox = {1, 1}; std::array elements = {4, 4}; GridType grid(bbox,elements); typedef GridType::LeafGridView GridView; GridView gridView = grid.leafGridView(); // { grid_setup_end } ///////////////////////////////////////////////////////// // Choose a finite element space ///////////////////////////////////////////////////////// // { function_space_basis_begin } // typedef Functions::TaylorHoodBasis TaylorHoodBasis; /*@\label{li:stokes_taylorhood_select_taylorhoodbasis}@*/ // TaylorHoodBasis taylorHoodBasis(gridView); using namespace Functions::BasisBuilder; static const std::size_t K = 1; // pressure order for Taylor-Hood auto taylorHoodBasis = makeBasis( gridView, composite( power( lagrange(), flatInterleaved()), lagrange() )); // { function_space_basis_end } ///////////////////////////////////////////////////////// // Stiffness matrix and right hand side vector ///////////////////////////////////////////////////////// // { linear_algebra_setup_begin } typedef BlockVector > > VectorType; typedef Matrix > > MatrixType; // { linear_algebra_setup_end } // { rhs_assembly_begin } VectorType rhs; typedef Dune::Functions::HierarchicVectorWrapper HierarchicVectorView; HierarchicVectorView(rhs).resize(taylorHoodBasis); rhs = 0; /*@\label{li:stokes_taylorhood_set_rhs_to_zero}@*/ // { rhs_assembly_end } ///////////////////////////////////////////////////////// // Assemble the system ///////////////////////////////////////////////////////// // { matrix_assembly_begin } MatrixType stiffnessMatrix; assembleStokesMatrix(taylorHoodBasis, stiffnessMatrix); /*@\label{li:stokes_taylorhood_call_to_assemblestokesmatrix}@*/ // { matrix_assembly_end } // Set Dirichlet values // Only velocity components have Dirichlet boundary values // { boundary_predicate_begin } using Coordinate = GridView::Codim<0> ::Geometry::GlobalCoordinate; auto boundaryIndicator = [&bbox](Coordinate x) { bool isBoundary = false; for (std::size_t j=0; j bbox[j] - 1e-8; return isBoundary; }; // { boundary_predicate_end } // { interpolate_boundary_predicate_begin } using namespace TypeTree::Indices; using BitVectorType = BlockVector > >; using HierarchicBitVectorView = Functions::HierarchicVectorWrapper; BitVectorType isBoundary; for(int i=0; i VelocityRange; auto&& velocityDirichletData = [](Coordinate x)->VelocityRange { return {0.0, double(x[0] < 1e-8)};}; interpolate(Functions::subspaceBasis(taylorHoodBasis, _0), HierarchicVectorView(rhs), velocityDirichletData, HierarchicBitVectorView(isBoundary)); // { interpolate_dirichlet_values_end } //////////////////////////////////////////// // Modify Dirichlet rows //////////////////////////////////////////// // loop over the matrix rows // { set_dirichlet_matrix_begin } for (size_t i=0; i op(stiffnessMatrix); // Fancy (but only) way to not have a preconditioner at all Richardson preconditioner(1.0); // Preconditioned conjugate-gradient solver RestartedGMResSolver solver(op, preconditioner, 1e-10, // desired residual reduction factor 500, // number of iterations between restarts 500, // maximum number of iterations 2); // verbosity of the solver // Object storing some statistics about the solving process InverseOperatorResult statistics; // Solve! solver.apply(x, rhs, statistics); // { stokes_solve_end } //////////////////////////////////////////////////////////////////////////// // Make a discrete function from the FE basis and the coefficient vector //////////////////////////////////////////////////////////////////////////// // { stokes_output_begin } using VelocityRange = FieldVector; using PressureRange = double; auto velocityFunction = Functions::makeDiscreteGlobalBasisFunction(Functions::subspaceBasis(taylorHoodBasis, _0), HierarchicVectorView(x)); auto pressureFunction = Functions::makeDiscreteGlobalBasisFunction(Functions::subspaceBasis(taylorHoodBasis, _1), HierarchicVectorView(x)); ////////////////////////////////////////////////////////////////////////////////////////////// // Write result to VTK file // We need to subsample, because VTK cannot natively display real second-order functions ////////////////////////////////////////////////////////////////////////////////////////////// SubsamplingVTKWriter vtkWriter(gridView,2); vtkWriter.addVertexData(velocityFunction, VTK::FieldInfo("velocity", VTK::FieldInfo::Type::vector, dim)); vtkWriter.addVertexData(pressureFunction, VTK::FieldInfo("pressure", VTK::FieldInfo::Type::scalar, 1)); vtkWriter.write("stokes-taylorhood-result"); // { stokes_output_end } } // Error handling catch (Exception e) { std::cout << e << std::endl; } dune-functions-2.5.1/stamp-vc000066400000000000000000000001511313314422100161240ustar00rootroot00000000000000A stamp file to signify that this directory comes from a version control system, not an unpacked tarball