LCOV - code coverage report
Current view: top level - ugbase/lib_disc/local_finite_element/lagrange - lagrange.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 31.4 % 593 186
Test Date: 2025-09-21 23:31:46 Functions: 17.1 % 461 79

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2010-2015:  G-CSC, Goethe University Frankfurt
       3              :  * Author: Andreas Vogel
       4              :  * 
       5              :  * This file is part of UG4.
       6              :  * 
       7              :  * UG4 is free software: you can redistribute it and/or modify it under the
       8              :  * terms of the GNU Lesser General Public License version 3 (as published by the
       9              :  * Free Software Foundation) with the following additional attribution
      10              :  * requirements (according to LGPL/GPL v3 §7):
      11              :  * 
      12              :  * (1) The following notice must be displayed in the Appropriate Legal Notices
      13              :  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
      14              :  * 
      15              :  * (2) The following notice must be displayed at a prominent place in the
      16              :  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
      17              :  * 
      18              :  * (3) The following bibliography is recommended for citation and must be
      19              :  * preserved in all covered files:
      20              :  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
      21              :  *   parallel geometric multigrid solver on hierarchically distributed grids.
      22              :  *   Computing and visualization in science 16, 4 (2013), 151-164"
      23              :  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
      24              :  *   flexible software system for simulating pde based models on high performance
      25              :  *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
      26              :  * 
      27              :  * This program is distributed in the hope that it will be useful,
      28              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      29              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      30              :  * GNU Lesser General Public License for more details.
      31              :  */
      32              : 
      33              : #ifndef __H__UG__LIB_DISC__LOCAL_SHAPE_FUNCTION_SET__LAGRANGE__LAGRANGE__
      34              : #define __H__UG__LIB_DISC__LOCAL_SHAPE_FUNCTION_SET__LAGRANGE__LAGRANGE__
      35              : 
      36              : #include "../common/lagrange1d.h"
      37              : #include "../local_finite_element_provider.h"
      38              : #include "../local_dof_set.h"
      39              : #include "lagrange_local_dof.h"
      40              : #include "lib_disc/common/multi_index.h"
      41              : #include "common/util/metaprogramming_util.h"
      42              : #include "lib_grid/grid/grid_base_objects.h"
      43              : 
      44              : namespace ug{
      45              : 
      46              : /// Lagrange Shape Function Set without virtual functions and fixed order
      47              : template <typename TRefElem, int TOrder>
      48              : class LagrangeLSFS;
      49              : 
      50              : /// Lagrange Shape Function Set without virtual functions and flexible order
      51              : template <typename TRefElem>
      52              : class FlexLagrangeLSFS;
      53              : 
      54              : 
      55              : ///////////////////////////////////////////////////////////////////////////////
      56              : // Vertex
      57              : ///////////////////////////////////////////////////////////////////////////////
      58              : 
      59              : /// specialization for Vertex
      60              : /**
      61              :  * Lagrange shape function of any order for the Reference Vertex
      62              :  * \tparam      TOrder          requested order
      63              :  */
      64              : template <int TOrder>
      65              : class LagrangeLSFS<ReferenceVertex, TOrder>
      66              :         : public LagrangeLDS<ReferenceVertex>,
      67              :           public BaseLSFS<LagrangeLSFS<ReferenceVertex, TOrder>, 0>
      68              : {
      69              :         private:
      70              :         ///     abbreviation for order
      71              :                 static const size_t p = TOrder;
      72              : 
      73              :         ///     base class
      74              :                 typedef BaseLSFS<LagrangeLSFS<ReferenceVertex, TOrder>, 0> base_type;
      75              : 
      76              :         public:
      77              :         ///     Shape type
      78              :                 typedef typename base_type::shape_type shape_type;
      79              : 
      80              :         ///     Gradient type
      81              :                 typedef typename base_type::grad_type grad_type;
      82              : 
      83              :         public:
      84              :         ///     Order of Shape functions
      85              :                 static const size_t order = TOrder;
      86              : 
      87              :         ///     Dimension, where shape functions are defined
      88              :                 static const int dim = ReferenceVertex::dim;
      89              : 
      90              :         /// Number of shape functions
      91              :                 static const size_t nsh = 1;
      92              : 
      93              :         public:
      94              :         ///     Constructor
      95            0 :                 LagrangeLSFS() {}
      96              : 
      97              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
      98              :                 inline bool continuous() const {return true;}
      99              : 
     100              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
     101            0 :                 inline size_t num_sh() const {return nsh;}
     102              : 
     103              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
     104              :                 inline bool position(size_t i, MathVector<dim>& pos) const
     105              :                 {
     106              :                         return true;
     107              :                 }
     108              : 
     109              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
     110              :                 inline shape_type shape(size_t i, const MathVector<dim>& x) const
     111              :                 {
     112              :                         return 1.0;
     113              :                 }
     114              : 
     115              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
     116              :                 inline void grad(grad_type& g, size_t i, const MathVector<dim>& x) const
     117              :                 {
     118              :                 }
     119              : };
     120              : 
     121              : /// specialization for Edges
     122              : /**
     123              :  * Lagrange shape function of any order for the Reference Edge
     124              :  */
     125              : template <>
     126              : class FlexLagrangeLSFS<ReferenceVertex>
     127              :         : public LagrangeLDS<ReferenceVertex>,
     128              :           public BaseLSFS<FlexLagrangeLSFS<ReferenceVertex>, 0>
     129              : {
     130              :         public:
     131              :         ///     Dimension, where shape functions are defined
     132              :                 static const int dim = ReferenceVertex::dim;
     133              : 
     134              :         public:
     135              :         ///     default Constructor
     136            0 :                 FlexLagrangeLSFS() {}
     137              : 
     138              :         ///     Constructor
     139              :                 FlexLagrangeLSFS(size_t order) {p = order;}
     140              : 
     141              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
     142              :                 inline bool continuous() const {return true;}
     143              : 
     144              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
     145            0 :                 inline size_t num_sh() const {return nsh;}
     146              : 
     147              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
     148              :                 inline bool position(size_t i, MathVector<dim>& pos) const
     149              :                 {
     150              :                         return true;
     151              :                 }
     152              : 
     153              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
     154              :                 inline shape_type shape(size_t i, const MathVector<dim>& x) const
     155              :                 {
     156              :                         return 1.0;
     157              :                 }
     158              : 
     159              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
     160              :                 inline void grad(grad_type& g, size_t i, const MathVector<dim>& x) const
     161              :                 {
     162              :                 }
     163              : 
     164              :         protected:
     165              :         ///     order
     166              :                 size_t p;
     167              : 
     168              :         /// Number of shape functions
     169              :                 static const size_t nsh = 1;
     170              : };
     171              : 
     172              : ///////////////////////////////////////////////////////////////////////////////
     173              : // Edge
     174              : ///////////////////////////////////////////////////////////////////////////////
     175              : 
     176              : /// specialization for Edges
     177              : /**
     178              :  * Lagrange shape function of any order for the Reference Edge
     179              :  * \tparam      TOrder          requested order
     180              :  */
     181              : template <int TOrder>
     182              : class LagrangeLSFS<ReferenceEdge, TOrder>
     183              :         : public LagrangeLDS<ReferenceEdge>,
     184              :           public BaseLSFS<LagrangeLSFS<ReferenceEdge, TOrder>, 1>
     185              : {
     186              :         private:
     187              :         ///     abbreviation for order
     188              :                 static const size_t p = TOrder;
     189              : 
     190              :         ///     base class
     191              :                 typedef BaseLSFS<LagrangeLSFS<ReferenceEdge, TOrder>, 1> base_type;
     192              : 
     193              :         public:
     194              :         ///     Shape type
     195              :                 typedef typename base_type::shape_type shape_type;
     196              : 
     197              :         ///     Gradient type
     198              :                 typedef typename base_type::grad_type grad_type;
     199              : 
     200              :         public:
     201              :         ///     Order of Shape functions
     202              :                 static const size_t order = TOrder;
     203              : 
     204              :         ///     Dimension, where shape functions are defined
     205              :                 static const int dim = ReferenceEdge::dim;
     206              : 
     207              :         /// Number of shape functions
     208              :                 static const size_t nsh = p+1;
     209              : 
     210              :         public:
     211              :         ///     Constructor
     212              :                 LagrangeLSFS();
     213              : 
     214              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
     215            0 :                 inline bool continuous() const {return true;}
     216              : 
     217              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
     218          720 :                 inline size_t num_sh() const {return nsh;}
     219              : 
     220              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
     221            0 :                 inline bool position(size_t i, MathVector<dim>& pos) const
     222              :                 {
     223           27 :                         pos = EquidistantLagrange1D::position(multi_index(i)[0], p);
     224            0 :                         return true;
     225              :                 }
     226              : 
     227              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
     228            0 :                 inline shape_type shape(size_t i, const MathVector<dim>& x) const
     229              :                 {
     230          778 :                         return m_vPolynom[multi_index(i)[0]].value(x[0]);
     231              :                 }
     232              : 
     233              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
     234            0 :                 inline void grad(grad_type& g, size_t i, const MathVector<dim>& x) const
     235              :                 {
     236          540 :                         g[0] = m_vDPolynom[multi_index(i)[0]].value(x[0]);
     237            0 :                 }
     238              : 
     239              :         ///     return Multi index for index i
     240            0 :                 inline const MathVector<dim,int>& multi_index(size_t i) const
     241              :                 {
     242              :                         check_index(i);
     243           28 :                         return m_vMultiIndex[i];
     244              :                 }
     245              : 
     246              :         ///     return the index for a multi_index
     247            9 :                 inline size_t index(const MathVector<dim,int>& ind) const
     248              :                 {
     249              :                         check_multi_index(ind);
     250           19 :                         for(size_t i=0; i<nsh; ++i)
     251           19 :                                 if(multi_index(i) == ind) return i;
     252            0 :                         UG_THROW("Index not found in LagrangeLSFS");
     253              :                 }
     254              : 
     255              :         ///     return Multi index for index i
     256            0 :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
     257              :                 {
     258              :                         check_index(i);
     259            0 :                         return MathVector<1,int>(i);
     260              :                 }
     261              : 
     262              :         ///     return the index for a multi_index
     263            0 :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
     264              :                 {
     265              :                         check_multi_index(ind);
     266            0 :                         return ind[0];
     267              :                 }
     268              : 
     269              :         ///     checks in debug mode that index is valid
     270            0 :                 inline void check_index(size_t i) const
     271              :                 {
     272              :                         UG_ASSERT(i < nsh, "Wrong index.");
     273            0 :                 }
     274              : 
     275              :         ///     checks in debug mode that multi-index is valid
     276            0 :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
     277              :                 {
     278              :                         UG_ASSERT(ind[0] < (int)nsh && ind[0] >= 0, "Wrong MultiIndex");
     279            0 :                 }
     280              : 
     281              :         protected:
     282              :                 Polynomial1D m_vPolynom[p+1];   ///< Shape Polynomials
     283              :                 Polynomial1D m_vDPolynom[p+1];  ///< Derivative of Shape Polynomial
     284              : 
     285              :                 MathVector<dim,int> m_vMultiIndex[nsh];
     286              : };
     287              : 
     288              : /// specialization for Edges
     289              : /**
     290              :  * Lagrange shape function of any order for the Reference Edge
     291              :  */
     292              : template <>
     293              : class FlexLagrangeLSFS<ReferenceEdge>
     294              :         : public LagrangeLDS<ReferenceEdge>,
     295              :           public BaseLSFS<FlexLagrangeLSFS<ReferenceEdge>, 1>
     296              : {
     297              :         public:
     298              :         ///     Dimension, where shape functions are defined
     299              :                 static const int dim = ReferenceEdge::dim;
     300              : 
     301              :         public:
     302              :         ///     default Constructor
     303            0 :                 FlexLagrangeLSFS() {set_order(1);}
     304              : 
     305              :         ///     Constructor
     306            0 :                 FlexLagrangeLSFS(size_t order) {set_order(order);}
     307              : 
     308              :         ///     sets the order
     309              :                 void set_order(size_t order);
     310              : 
     311              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
     312              :                 inline bool continuous() const {return true;}
     313              : 
     314              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
     315            0 :                 inline size_t num_sh() const {return nsh;}
     316              : 
     317              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
     318              :                 inline bool position(size_t i, MathVector<dim>& pos) const
     319              :                 {
     320            0 :                         pos = EquidistantLagrange1D::position(multi_index(i)[0], p);
     321              :                         return true;
     322              :                 }
     323              : 
     324              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
     325            0 :                 inline shape_type shape(size_t i, const MathVector<dim>& x) const
     326              :                 {
     327            0 :                         return m_vPolynom[multi_index(i)[0]].value(x[0]);
     328              :                 }
     329              : 
     330              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
     331            0 :                 inline void grad(grad_type& g, size_t i, const MathVector<dim>& x) const
     332              :                 {
     333            0 :                         g[0] = m_vDPolynom[multi_index(i)[0]].value(x[0]);
     334            0 :                 }
     335              : 
     336              :         ///     return Multi index for index i
     337              :                 inline const MathVector<dim,int>& multi_index(size_t i) const
     338              :                 {
     339              :                         check_index(i);
     340              :                         return m_vMultiIndex[i];
     341              :                 }
     342              : 
     343              :         ///     return the index for a multi_index
     344            0 :                 inline size_t index(const MathVector<dim,int>& ind) const
     345              :                 {
     346              :                         check_multi_index(ind);
     347            0 :                         for(size_t i=0; i<nsh; ++i)
     348            0 :                                 if(multi_index(i) == ind) return i;
     349            0 :                         UG_THROW("Index not found in LagrangeLSFS");
     350              :                 }
     351              : 
     352              :         ///     return Multi index for index i
     353              :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
     354              :                 {
     355              :                         check_index(i);
     356              :                         return MathVector<1,int>(i);
     357              :                 }
     358              : 
     359              :         ///     return the index for a multi_index
     360              :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
     361              :                 {
     362              :                         check_multi_index(ind);
     363              :                         return ind[0];
     364              :                 }
     365              : 
     366              :         ///     checks in debug mode that index is valid
     367              :                 inline void check_index(size_t i) const
     368              :                 {
     369              :                         UG_ASSERT(i < nsh, "Wrong index.");
     370              :                 }
     371              : 
     372              :         ///     checks in debug mode that multi-index is valid
     373              :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
     374              :                 {
     375              :                         UG_ASSERT(ind[0] < (int)nsh && ind[0] >= 0, "Wrong MultiIndex");
     376              :                 }
     377              : 
     378              :         protected:
     379              :         ///     order
     380              :                 size_t p;
     381              : 
     382              :         /// Number of shape functions
     383              :                 size_t nsh;
     384              : 
     385              :                 std::vector<Polynomial1D> m_vPolynom;     ///< Shape Polynomials
     386              :                 std::vector<Polynomial1D> m_vDPolynom;    ///< Derivative of Shape Polynomial
     387              : 
     388              :                 std::vector<MathVector<dim,int> > m_vMultiIndex;
     389              : };
     390              : 
     391              : ///////////////////////////////////////////////////////////////////////////////
     392              : // Triangle
     393              : ///////////////////////////////////////////////////////////////////////////////
     394              : 
     395              : template <int TOrder>
     396              : class LagrangeLSFS<ReferenceTriangle, TOrder>
     397              :         : public LagrangeLDS<ReferenceTriangle>,
     398              :           public BaseLSFS<LagrangeLSFS<ReferenceTriangle, TOrder>, 2>
     399              : {
     400              :         private:
     401              :         ///     abbreviation for order
     402              :                 static const size_t p = TOrder;
     403              : 
     404              :         ///     base class
     405              :                 typedef BaseLSFS<LagrangeLSFS<ReferenceTriangle, TOrder>, 2> base_type;
     406              : 
     407              :         public:
     408              :         ///     Shape type
     409              :                 typedef typename base_type::shape_type shape_type;
     410              : 
     411              :         ///     Gradient type
     412              :                 typedef typename base_type::grad_type grad_type;
     413              : 
     414              :         public:
     415              :         ///     Order of Shape functions
     416              :                 static const size_t order = TOrder;
     417              : 
     418              :         ///     Dimension, where shape functions are defined
     419              :                 static const int dim = ReferenceTriangle::dim;
     420              : 
     421              :         /// Number of shape functions
     422              :                 static const size_t nsh = BinomialCoefficient<dim + p, p>::value;
     423              : 
     424              :         public:
     425              :         ///     Constructor
     426              :                 LagrangeLSFS();
     427              : 
     428              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
     429            0 :                 inline bool continuous() const {return true;}
     430              : 
     431              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
     432         1320 :                 inline size_t num_sh() const {return nsh;}
     433              : 
     434              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
     435            0 :                 inline bool position(size_t i, MathVector<dim>& pos) const
     436              :                 {
     437              :                 //      get Multi Index
     438              :                         MathVector<dim,int> ind = multi_index(i);
     439              : 
     440              :                 //      set position
     441          141 :                         for(int d = 0; d < dim; ++d)
     442           94 :                                 pos[d] = TruncatedEquidistantLagrange1D::position(ind[d], p);
     443              : 
     444            0 :                         return true;
     445              :                 }
     446              : 
     447              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
     448            0 :                 inline number shape(const size_t i, const MathVector<dim>& x) const
     449              :                 {
     450              :                 //      forward
     451         1810 :                         return shape(multi_index(i), x);
     452              :                 }
     453              : 
     454              :         ///     shape value for a Multi Index
     455         1810 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
     456              :                 {
     457              :                         check_multi_index(ind);
     458              :                         //ReferenceTriangle::check_position(x);
     459              : 
     460              :                 //      get adjoint barycentric index
     461         1810 :                         const size_t i0 = p - ind[0] - ind[1];
     462         1810 :                         const number x0 = 1.0 - x[0] - x[1];
     463              : 
     464         1810 :                         return    m_vPolynom[ ind[0] ].value(x[0])
     465         1810 :                                         * m_vPolynom[ ind[1] ].value(x[1])
     466         1810 :                                         * m_vPolynom[ i0     ].value(x0);
     467              :                 }
     468              : 
     469              : 
     470              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
     471            0 :                 inline void grad(grad_type& g, const size_t i,      const MathVector<dim>& x) const
     472              :                 {
     473          760 :                         grad(g, multi_index(i), x);
     474            0 :                 }
     475              : 
     476              :         ///     evaluates the gradient
     477          760 :                 inline void grad(grad_type& g, const MathVector<dim,int> ind,
     478              :                                                                    const MathVector<dim>& x) const
     479              :                 {
     480              :                         check_multi_index(ind);
     481              :                         //ReferenceTriangle::check_position(x);
     482              : 
     483              :                 //      get adjoint barycentric index and position
     484          760 :                         const size_t i0 = p - ind[0] - ind[1];
     485          760 :                         const number x0 = 1.0 - x[0] - x[1];
     486              : 
     487              :                         UG_ASSERT(i0 <= (int)p, "Wrong Multiindex.");
     488              :                         UG_ASSERT(x0 <= 1.0+SMALL && x0 >= -SMALL, "Wrong Position.");
     489              : 
     490              :                 //      loop dimensions
     491         2280 :                         for(int d = 0; d < dim; ++d)
     492              :                         {
     493         1520 :                                 g[d] = m_vDPolynom[ind[d]].value(x[d])
     494         1520 :                                                 * m_vPolynom[i0].value(x0);
     495         1520 :                                 g[d] += (-1) * m_vDPolynom[i0].value(x0)
     496         1520 :                                                    * m_vPolynom[ind[d]].value(x[d]);
     497              : 
     498              :                         //      multiply by all functions not depending on x[d]
     499         4560 :                                 for(int d2 = 0; d2 < dim; ++d2)
     500              :                                 {
     501              :                                 //      skip own value
     502         3040 :                                         if(d2 == d) continue;
     503              : 
     504         3040 :                                         g[d] *= m_vPolynom[ind[d2]].value(x[d2]);
     505              :                                 }
     506              :                         }
     507          760 :                 }
     508              : 
     509              :         ///     return Multi index for index i
     510            0 :                 inline const MathVector<dim,int>& multi_index(size_t i) const
     511              :                 {
     512              :                         check_index(i);
     513         1819 :                         return m_vMultiIndex[i];
     514              :                 }
     515              : 
     516              :         ///     return the index for a multi_index
     517           19 :                 inline size_t index(const MathVector<dim,int>& ind) const
     518              :                 {
     519              :                         check_multi_index(ind);
     520           82 :                         for(size_t i=0; i<nsh; ++i)
     521           82 :                                 if(multi_index(i) == ind) return i;
     522            0 :                         UG_THROW("Index not found in LagrangeLSFS");
     523              :                 }
     524              : 
     525              :         ///     return the index for a multi_index
     526            0 :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
     527              :                 {
     528              :                         check_multi_index(ind);
     529              : 
     530            0 :                         size_t res = ind[0];
     531            0 :                         for(int i = 0; i < ind[1]; ++i)
     532            0 :                                 res += (p+1-i);
     533              : 
     534              :                         check_index(res);
     535            0 :                         return res;
     536              :                 }
     537              : 
     538              :         ///     return the multi_index for an index
     539            0 :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
     540              :                 {
     541              :                         check_index(i);
     542              : 
     543            0 :                         int i0 = i, i1;
     544            0 :                         for(i1 = 0; i1 < (int)p; ++i1)
     545              :                         {
     546            0 :                                 const int diff = i0 - (p+1-i1);
     547            0 :                                 if(diff < 0) break;
     548              :                                 i0 = diff;
     549              :                         }
     550              : 
     551              :                         UG_ASSERT(i0 >= 0, "i0 is negative ("<<i0<<")");
     552              :                         UG_ASSERT(i1 >= 0, "i1 is negative ("<<i1<<")");
     553            0 :                         return MathVector<dim,int>( i0, i1 );
     554              :                 }
     555              : 
     556              :         ///     checks in debug mode that index is valid
     557            0 :                 inline void check_index(size_t i) const
     558              :                 {
     559              :                         UG_ASSERT(i < nsh, "Wrong index.");
     560            0 :                 }
     561              : 
     562              :         ///     checks in debug mode that multi-index is valid
     563            0 :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
     564              :                 {
     565              :                         UG_ASSERT(ind[0] <= (int)p && ind[0]>=0, "Wrong Multiindex.");
     566              :                         UG_ASSERT(ind[1] <= (int)p && ind[0]>=0, "Wrong Multiindex.");
     567              :                         UG_ASSERT(ind[0] + ind[1] <= (int)p && ind[0]>=0, "Wrong Multiindex.");
     568            0 :                 }
     569              : 
     570              :         private:
     571              :                 Polynomial1D m_vPolynom[p+1];
     572              :                 Polynomial1D m_vDPolynom[p+1];
     573              : 
     574              :                 MathVector<dim,int> m_vMultiIndex[nsh];
     575              : };
     576              : 
     577              : 
     578              : template <>
     579              : class FlexLagrangeLSFS<ReferenceTriangle>
     580              :         : public LagrangeLDS<ReferenceTriangle>,
     581              :           public BaseLSFS<FlexLagrangeLSFS<ReferenceTriangle>, 2>
     582              : {
     583              :         public:
     584              :         ///     Dimension, where shape functions are defined
     585              :                 static const int dim = ReferenceTriangle::dim;
     586              : 
     587              :         public:
     588              :         ///     default Constructor
     589            0 :                 FlexLagrangeLSFS() {set_order(1);}
     590              : 
     591              :         ///     Constructor
     592            0 :                 FlexLagrangeLSFS(size_t order) {set_order(order);}
     593              : 
     594              :         ///     sets the order
     595              :                 void set_order(size_t order);
     596              : 
     597              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
     598              :                 inline bool continuous() const {return true;}
     599              : 
     600              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
     601            0 :                 inline size_t num_sh() const {return nsh;}
     602              : 
     603              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
     604              :                 inline bool position(size_t i, MathVector<dim>& pos) const
     605              :                 {
     606              :                 //      get Multi Index
     607              :                         MathVector<dim,int> ind = multi_index(i);
     608              : 
     609              :                 //      set position
     610            0 :                         for(int d = 0; d < dim; ++d)
     611            0 :                                 pos[d] = TruncatedEquidistantLagrange1D::position(ind[d], p);
     612              : 
     613              :                         return true;
     614              :                 }
     615              : 
     616              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
     617              :                 inline number shape(const size_t i, const MathVector<dim>& x) const
     618              :                 {
     619              :                 //      forward
     620            0 :                         return shape(multi_index(i), x);
     621              :                 }
     622              : 
     623              :         ///     shape value for a Multi Index
     624            0 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
     625              :                 {
     626              :                         check_multi_index(ind);
     627              :                         //ReferenceTriangle::check_position(x);
     628              : 
     629              :                 //      get adjoint barycentric index
     630            0 :                         const size_t i0 = p - ind[0] - ind[1];
     631            0 :                         const number x0 = 1.0 - x[0] - x[1];
     632              : 
     633              :                         return    m_vPolynom[ ind[0] ].value(x[0])
     634            0 :                                         * m_vPolynom[ ind[1] ].value(x[1])
     635            0 :                                         * m_vPolynom[ i0     ].value(x0);
     636              :                 }
     637              : 
     638              : 
     639              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
     640              :                 inline void grad(grad_type& g, const size_t i,      const MathVector<dim>& x) const
     641              :                 {
     642            0 :                         grad(g, multi_index(i), x);
     643              :                 }
     644              : 
     645              :         ///     evaluates the gradient
     646            0 :                 inline void grad(grad_type& g, const MathVector<dim,int> ind,
     647              :                                                                    const MathVector<dim>& x) const
     648              :                 {
     649              :                         check_multi_index(ind);
     650              :                         //ReferenceTriangle::check_position(x);
     651              : 
     652              :                 //      get adjoint barycentric index and position
     653            0 :                         const int i0 = p - ind[0] - ind[1];
     654            0 :                         const number x0 = 1.0 - x[0] - x[1];
     655              : 
     656              :                         UG_ASSERT(i0 <= (int)p && i0 >= 0, "Wrong Multiindex.");
     657              :                         UG_ASSERT(x0 <= 1.0+SMALL && x0 >= -SMALL, "Wrong Position.");
     658              : 
     659              :                 //      loop dimensions
     660            0 :                         for(int d = 0; d < dim; ++d)
     661              :                         {
     662            0 :                                 g[d] = m_vDPolynom[ind[d]].value(x[d])
     663            0 :                                                 * m_vPolynom[i0].value(x0);
     664            0 :                                 g[d] += (-1) * m_vDPolynom[i0].value(x0)
     665            0 :                                                    * m_vPolynom[ind[d]].value(x[d]);
     666              : 
     667              :                         //      multiply by all functions not depending on x[d]
     668            0 :                                 for(int d2 = 0; d2 < dim; ++d2)
     669              :                                 {
     670              :                                 //      skip own value
     671            0 :                                         if(d2 == d) continue;
     672              : 
     673            0 :                                         g[d] *= m_vPolynom[ind[d2]].value(x[d2]);
     674              :                                 }
     675              :                         }
     676            0 :                 }
     677              : 
     678              :         ///     return Multi index for index i
     679              :                 inline const MathVector<dim,int>& multi_index(size_t i) const
     680              :                 {
     681              :                         check_index(i);
     682              :                         return m_vMultiIndex[i];
     683              :                 }
     684              : 
     685              :         ///     return the index for a multi_index
     686            0 :                 inline size_t index(const MathVector<dim,int>& ind) const
     687              :                 {
     688              :                         check_multi_index(ind);
     689            0 :                         for(size_t i=0; i<nsh; ++i)
     690            0 :                                 if(multi_index(i) == ind) return i;
     691            0 :                         UG_THROW("Index not found in LagrangeLSFS");
     692              :                 }
     693              : 
     694              :         ///     return the index for a multi_index
     695              :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
     696              :                 {
     697              :                         check_multi_index(ind);
     698              : 
     699              :                         size_t res = ind[0];
     700              :                         for(int i = 0; i < ind[1]; ++i)
     701              :                                 res += (p+1-i);
     702              : 
     703              :                         check_index(res);
     704              :                         return res;
     705              :                 }
     706              : 
     707              :         ///     return the multi_index for an index
     708              :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
     709              :                 {
     710              :                         check_index(i);
     711              : 
     712              :                         int i0 = i, i1;
     713              :                         for(i1 = 0; i1 < (int)p; ++i1)
     714              :                         {
     715              :                                 const int diff = i0 - (p+1-i1);
     716              :                                 if(diff < 0) break;
     717              :                                 i0 = diff;
     718              :                         }
     719              : 
     720              :                         UG_ASSERT(i0 >= 0, "i0 is negative ("<<i0<<")");
     721              :                         UG_ASSERT(i1 >= 0, "i1 is negative ("<<i1<<")");
     722              :                         return MathVector<dim,int>( i0, i1 );
     723              :                 }
     724              : 
     725              :         ///     checks in debug mode that index is valid
     726              :                 inline void check_index(size_t i) const
     727              :                 {
     728              :                         UG_ASSERT(i < nsh, "Wrong index.");
     729              :                 }
     730              : 
     731              :         ///     checks in debug mode that multi-index is valid
     732              :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
     733              :                 {
     734              :                         UG_ASSERT(ind[0] <= (int)p && ind[0]>=0, "Wrong Multiindex.");
     735              :                         UG_ASSERT(ind[1] <= (int)p && ind[0]>=0, "Wrong Multiindex.");
     736              :                         UG_ASSERT(ind[0] + ind[1] <= (int)p && ind[0]>=0, "Wrong Multiindex.");
     737              :                 }
     738              : 
     739              :         private:
     740              :         ///     order
     741              :                 size_t p;
     742              : 
     743              :         /// Number of shape functions
     744              :                 size_t nsh;
     745              : 
     746              :                 std::vector<Polynomial1D> m_vPolynom;     ///< Shape Polynomials
     747              :                 std::vector<Polynomial1D> m_vDPolynom;    ///< Derivative of Shape Polynomial
     748              : 
     749              :                 std::vector<MathVector<dim,int> > m_vMultiIndex;
     750              : };
     751              : 
     752              : ///////////////////////////////////////////////////////////////////////////////
     753              : // Quadrilateral
     754              : ///////////////////////////////////////////////////////////////////////////////
     755              : 
     756              : template <int TOrder>
     757              : class LagrangeLSFS<ReferenceQuadrilateral, TOrder>
     758              :         : public LagrangeLDS<ReferenceQuadrilateral>,
     759              :           public BaseLSFS<LagrangeLSFS<ReferenceQuadrilateral, TOrder>, 2>
     760              : {
     761              :         private:
     762              :         ///     abbreviation for order
     763              :                 static const size_t p = TOrder;
     764              : 
     765              :         ///     base class
     766              :                 typedef BaseLSFS<LagrangeLSFS<ReferenceQuadrilateral, TOrder>, 2> base_type;
     767              : 
     768              :         public:
     769              :         ///     Shape type
     770              :                 typedef typename base_type::shape_type shape_type;
     771              : 
     772              :         ///     Gradient type
     773              :                 typedef typename base_type::grad_type grad_type;
     774              : 
     775              :         public:
     776              :         ///     Order of Shape functions
     777              :                 static const size_t order = TOrder;
     778              : 
     779              :         ///     Dimension, where shape functions are defined
     780              :                 static const int dim = ReferenceQuadrilateral::dim;
     781              : 
     782              :         /// Number of shape functions
     783              :                 static const size_t nsh = (p+1)*(p+1);
     784              : 
     785              :         public:
     786              :         ///     Constructor
     787              :                 LagrangeLSFS();
     788              : 
     789              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
     790            0 :                 inline bool continuous() const {return true;}
     791              : 
     792              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
     793         1920 :                 inline size_t num_sh() const {return nsh;}
     794              : 
     795              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
     796            0 :                 inline bool position(size_t i, MathVector<dim>& pos) const
     797              :                 {
     798              :                 //      get Multi Index
     799              :                         MathVector<dim,int> ind = multi_index(i);
     800              : 
     801              :                 //      set position
     802          213 :                         for(int d = 0; d < dim; ++d)
     803          142 :                                 pos[d] = EquidistantLagrange1D::position(ind[d], p);
     804              : 
     805            0 :                         return true;
     806              :                 }
     807              : 
     808              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
     809            0 :                 inline number shape(const size_t i, const MathVector<dim>& x) const
     810              :                 {
     811              :                 //      forward
     812         3026 :                         return shape(multi_index(i), x);
     813              :                 }
     814              : 
     815              :         ///     shape value for a Multi Index
     816         3026 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
     817              :                 {
     818              :                         check_multi_index(ind);
     819              :                         //ReferenceQuadrilateral::check_position(x);
     820              : 
     821         3026 :                         return    m_vPolynom[ ind[0] ].value(x[0])
     822         3026 :                                         * m_vPolynom[ ind[1] ].value(x[1]);
     823              :                 }
     824              : 
     825              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
     826            0 :                 inline void grad(grad_type& g, const size_t i, const MathVector<dim>& x) const
     827              :                 {
     828         1160 :                         grad(g, multi_index(i), x);
     829            0 :                 }
     830              : 
     831              :         /// evaluates the gradient
     832         1160 :                 inline void grad(grad_type& g, const MathVector<dim,int> ind,
     833              :                                                 const MathVector<dim>& x) const
     834              :                 {
     835              :                         check_multi_index(ind);
     836              :                         //ReferenceQuadrilateral::check_position(x);
     837              : 
     838              :                 //      loop dimensions
     839         3480 :                         for(int d = 0; d < dim; ++d)
     840              :                         {
     841         2320 :                                 g[d] = m_vDPolynom[ind[d]].value(x[d]);
     842              : 
     843              :                         //      multiply by all functions not depending on x[d]
     844         6960 :                                 for(int d2 = 0; d2 < dim; ++d2)
     845              :                                 {
     846              :                                 //      skip own value
     847         4640 :                                         if(d2 == d) continue;
     848              : 
     849         4640 :                                         g[d] *= m_vPolynom[ind[d2]].value(x[d2]);
     850              :                                 }
     851              :                         }
     852         1160 :                 }
     853              : 
     854              :         ///     return Multi index for index i
     855            0 :                 inline const MathVector<dim,int>& multi_index(size_t i) const
     856              :                 {
     857              :                         check_index(i);
     858         3039 :                         return m_vMultiIndex[i];
     859              :                 }
     860              : 
     861              :         ///     return the index for a multi_index
     862           29 :                 inline size_t index(const MathVector<dim,int>& ind) const
     863              :                 {
     864              :                         check_multi_index(ind);
     865          191 :                         for(size_t i=0; i<nsh; ++i)
     866          191 :                                 if(multi_index(i) == ind) return i;
     867            0 :                         UG_THROW("Index not found in LagrangeLSFS");
     868              :                 }
     869              : 
     870              :         ///     return the index for a multi_index
     871            0 :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
     872              :                 {
     873              :                         check_multi_index(ind);
     874              : 
     875            0 :                         return ind[1] * (p+1) + ind[0];
     876              :                 }
     877              : 
     878              :         ///     return the multi_index for an index
     879            0 :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
     880              :                 {
     881              :                         check_index(i);
     882              : 
     883            0 :                         return MathVector<dim,int>( i%(p+1), i/(p+1) );
     884              :                 }
     885              : 
     886              :         ///     checks in debug mode that index is valid
     887            0 :                 inline void check_index(size_t i) const
     888              :                 {
     889              :                         UG_ASSERT(i < nsh, "Wrong index.");
     890            0 :                 }
     891              : 
     892              :         ///     checks in debug mode that multi-index is valid
     893            0 :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
     894              :                 {
     895              :                         UG_ASSERT(ind[0] <= (int)p && ind[0] >= 0, "Wrong Multiindex.");
     896              :                         UG_ASSERT(ind[1] <= (int)p && ind[1] >= 0, "Wrong Multiindex.");
     897            0 :                 }
     898              : 
     899              :         private:
     900              :                 Polynomial1D m_vPolynom[p+1];
     901              :                 Polynomial1D m_vDPolynom[p+1];
     902              : 
     903              :                 MathVector<dim,int> m_vMultiIndex[nsh];
     904              : };
     905              : 
     906              : 
     907              : template <>
     908              : class FlexLagrangeLSFS<ReferenceQuadrilateral>
     909              :         : public LagrangeLDS<ReferenceQuadrilateral>,
     910              :           public BaseLSFS<FlexLagrangeLSFS<ReferenceQuadrilateral>, 2>
     911              : {
     912              :         public:
     913              :         ///     Dimension, where shape functions are defined
     914              :                 static const int dim = ReferenceQuadrilateral::dim;
     915              : 
     916              :         public:
     917              :         ///     default Constructor
     918            0 :                 FlexLagrangeLSFS() {set_order(1);}
     919              : 
     920              :         ///     Constructor
     921            0 :                 FlexLagrangeLSFS(size_t order) {set_order(order);}
     922              : 
     923              :         ///     sets the order
     924              :                 void set_order(size_t order);
     925              : 
     926              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
     927              :                 inline bool continuous() const {return true;}
     928              : 
     929              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
     930            0 :                 inline size_t num_sh() const {return nsh;}
     931              : 
     932              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
     933              :                 inline bool position(size_t i, MathVector<dim>& pos) const
     934              :                 {
     935              :                 //      get Multi Index
     936              :                         MathVector<dim,int> ind = multi_index(i);
     937              : 
     938              :                 //      set position
     939            0 :                         for(int d = 0; d < dim; ++d)
     940            0 :                                 pos[d] = EquidistantLagrange1D::position(ind[d], p);
     941              : 
     942              :                         return true;
     943              :                 }
     944              : 
     945              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
     946              :                 inline number shape(const size_t i, const MathVector<dim>& x) const
     947              :                 {
     948              :                 //      forward
     949            0 :                         return shape(multi_index(i), x);
     950              :                 }
     951              : 
     952              :         ///     shape value for a Multi Index
     953            0 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
     954              :                 {
     955              :                         check_multi_index(ind);
     956              :                         //ReferenceQuadrilateral::check_position(x);
     957              : 
     958            0 :                         return    m_vPolynom[ ind[0] ].value(x[0])
     959            0 :                                         * m_vPolynom[ ind[1] ].value(x[1]);
     960              :                 }
     961              : 
     962              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
     963              :                 inline void grad(grad_type& g, const size_t i, const MathVector<dim>& x) const
     964              :                 {
     965            0 :                         grad(g, multi_index(i), x);
     966              :                 }
     967              : 
     968              :         /// evaluates the gradient
     969            0 :                 inline void grad(grad_type& g, const MathVector<dim,int> ind,
     970              :                                                 const MathVector<dim>& x) const
     971              :                 {
     972              :                         check_multi_index(ind);
     973              :                         //ReferenceQuadrilateral::check_position(x);
     974              : 
     975              :                 //      loop dimensions
     976            0 :                         for(int d = 0; d < dim; ++d)
     977              :                         {
     978            0 :                                 g[d] = m_vDPolynom[ind[d]].value(x[d]);
     979              : 
     980              :                         //      multiply by all functions not depending on x[d]
     981            0 :                                 for(int d2 = 0; d2 < dim; ++d2)
     982              :                                 {
     983              :                                 //      skip own value
     984            0 :                                         if(d2 == d) continue;
     985              : 
     986            0 :                                         g[d] *= m_vPolynom[ind[d2]].value(x[d2]);
     987              :                                 }
     988              :                         }
     989            0 :                 }
     990              : 
     991              :         ///     return Multi index for index i
     992              :                 inline const MathVector<dim,int>& multi_index(size_t i) const
     993              :                 {
     994              :                         check_index(i);
     995              :                         return m_vMultiIndex[i];
     996              :                 }
     997              : 
     998              :         ///     return the index for a multi_index
     999            0 :                 inline size_t index(const MathVector<dim,int>& ind) const
    1000              :                 {
    1001              :                         check_multi_index(ind);
    1002            0 :                         for(size_t i=0; i<nsh; ++i)
    1003            0 :                                 if(multi_index(i) == ind) return i;
    1004            0 :                         UG_THROW("Index not found in LagrangeLSFS");
    1005              :                 }
    1006              : 
    1007              :         ///     return the index for a multi_index
    1008              :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
    1009              :                 {
    1010              :                         check_multi_index(ind);
    1011              : 
    1012              :                         return ind[1] * (p+1) + ind[0];
    1013              :                 }
    1014              : 
    1015              :         ///     return the multi_index for an index
    1016              :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
    1017              :                 {
    1018              :                         check_index(i);
    1019              : 
    1020              :                         return MathVector<dim,int>( i%(p+1), i/(p+1) );
    1021              :                 }
    1022              : 
    1023              :         ///     checks in debug mode that index is valid
    1024              :                 inline void check_index(size_t i) const
    1025              :                 {
    1026              :                         UG_ASSERT(i < nsh, "Wrong index.");
    1027              :                 }
    1028              : 
    1029              :         ///     checks in debug mode that multi-index is valid
    1030              :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
    1031              :                 {
    1032              :                         UG_ASSERT(ind[0] <= (int)p && ind[0] >= 0, "Wrong Multiindex.");
    1033              :                         UG_ASSERT(ind[1] <= (int)p && ind[1] >= 0, "Wrong Multiindex.");
    1034              :                 }
    1035              : 
    1036              :         private:
    1037              :         ///     order
    1038              :                 size_t p;
    1039              : 
    1040              :         /// Number of shape functions
    1041              :                 size_t nsh;
    1042              : 
    1043              :                 std::vector<Polynomial1D> m_vPolynom;     ///< Shape Polynomials
    1044              :                 std::vector<Polynomial1D> m_vDPolynom;    ///< Derivative of Shape Polynomial
    1045              : 
    1046              :                 std::vector<MathVector<dim,int> > m_vMultiIndex;
    1047              : };
    1048              : 
    1049              : ///////////////////////////////////////////////////////////////////////////////
    1050              : // Tetrahedron
    1051              : ///////////////////////////////////////////////////////////////////////////////
    1052              : 
    1053              : template <int TOrder>
    1054              : class LagrangeLSFS<ReferenceTetrahedron, TOrder>
    1055              :         : public LagrangeLDS<ReferenceTetrahedron>,
    1056              :           public BaseLSFS<LagrangeLSFS<ReferenceTetrahedron, TOrder>, 3>
    1057              : {
    1058              :         private:
    1059              :         ///     abbreviation for order
    1060              :                 static const size_t p = TOrder;
    1061              : 
    1062              :         ///     base class
    1063              :                 typedef BaseLSFS<LagrangeLSFS<ReferenceTetrahedron, TOrder>, 3> base_type;
    1064              : 
    1065              :         public:
    1066              :         ///     Shape type
    1067              :                 typedef typename base_type::shape_type shape_type;
    1068              : 
    1069              :         ///     Gradient type
    1070              :                 typedef typename base_type::grad_type grad_type;
    1071              : 
    1072              :         public:
    1073              :         ///     Order of Shape functions
    1074              :                 static const size_t order = TOrder;
    1075              : 
    1076              :         ///     Dimension, where shape functions are defined
    1077              :                 static const int dim = ReferenceTetrahedron::dim;
    1078              : 
    1079              :         /// Number of shape functions
    1080              :                 static const size_t nsh = BinomialCoefficient<dim + p, p>::value;
    1081              : 
    1082              :         public:
    1083              :         ///     Constructor
    1084              :                 LagrangeLSFS();
    1085              : 
    1086              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
    1087            0 :                 inline bool continuous() const {return true;}
    1088              : 
    1089              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
    1090         2220 :                 inline size_t num_sh() const {return nsh;}
    1091              : 
    1092              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
    1093            0 :                 inline bool position(size_t i, MathVector<dim>& pos) const
    1094              :                 {
    1095              :                 //      get Multi Index
    1096              :                         MathVector<dim,int> ind = multi_index(i);
    1097              : 
    1098              :                 //      set position
    1099          288 :                         for(int d = 0; d < dim; ++d)
    1100          216 :                                 pos[d] = TruncatedEquidistantLagrange1D::position(ind[d], p);
    1101              : 
    1102            0 :                         return true;
    1103              :                 }
    1104              : 
    1105              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
    1106            0 :                 inline number shape(const size_t i, const MathVector<dim>& x) const
    1107              :                 {
    1108              :                 //      forward
    1109         3752 :                         return shape(multi_index(i), x);
    1110              :                 }
    1111              : 
    1112              :         ///     shape value for a Multi Index
    1113         3752 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
    1114              :                 {
    1115              :                         check_multi_index(ind);
    1116              :                         //ReferenceTetrahedron::check_position(x);
    1117              : 
    1118              :                 //      get adjoint barycentric index
    1119         3752 :                         const size_t i0 = p - ind[0] - ind[1] - ind[2];
    1120         3752 :                         const number x0 = 1.0 - x[0] - x[1] - x[2];
    1121              : 
    1122         3752 :                         return    m_vPolynom[ ind[0] ].value(x[0])
    1123         3752 :                                         * m_vPolynom[ ind[1] ].value(x[1])
    1124         3752 :                                         * m_vPolynom[ ind[2] ].value(x[2])
    1125         3752 :                                         * m_vPolynom[ i0 ].value(x0);
    1126              :                 }
    1127              : 
    1128              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
    1129         1360 :                 inline void grad(grad_type& g, const size_t i, const MathVector<dim>& x) const
    1130              :                 {
    1131         1360 :                         grad(g, multi_index(i), x);
    1132         1360 :                 }
    1133              : 
    1134              :         ///     evaluates the gradient
    1135         1360 :                 inline void grad(grad_type& g, const MathVector<dim,int> ind,
    1136              :                                                             const MathVector<dim>& x) const
    1137              :                 {
    1138              :                         check_multi_index(ind);
    1139              :                         //ReferenceTetrahedron::check_position(x);
    1140              : 
    1141              :                 //      get adjoint barycentric index and position
    1142         1360 :                         const size_t i0 = p - ind[0] - ind[1] - ind[2];
    1143         1360 :                         const number x0 = 1 - x[0] - x[1] - x[2];
    1144              : 
    1145              :                         UG_ASSERT(i0 <= p, "Wrong Multiindex.");
    1146              :                         UG_ASSERT(x0 <= 1.0+SMALL && x0 >= -SMALL, "Wrong Position.");
    1147              : 
    1148              :                 //      loop dimensions
    1149         5440 :                         for(int d = 0; d < dim; ++d)
    1150              :                         {
    1151         4080 :                                 g[d] = m_vDPolynom[ind[d]].value(x[d])
    1152         4080 :                                                 * m_vPolynom[i0].value(x0);
    1153         4080 :                                 g[d] += (-1) * m_vDPolynom[i0].value(x0)
    1154         4080 :                                                    * m_vPolynom[ind[d]].value(x[d]);
    1155              : 
    1156              :                         //      multiply by all functions not depending on x[d]
    1157        16320 :                                 for(int d2 = 0; d2 < dim; ++d2)
    1158              :                                 {
    1159              :                                 //      skip own value
    1160        12240 :                                         if(d2 == d) continue;
    1161              : 
    1162        16320 :                                         g[d] *= m_vPolynom[ind[d2]].value(x[d2]);
    1163              :                                 }
    1164              :                         }
    1165         1360 :                 }
    1166              : 
    1167              :         ///     return Multi index for index i
    1168            0 :                 inline const MathVector<dim,int>& multi_index(size_t i) const
    1169              :                 {
    1170              :                         check_index(i);
    1171         3756 :                         return m_vMultiIndex[i];
    1172              :                 }
    1173              : 
    1174              :         ///     return the index for a multi_index
    1175           34 :                 inline size_t index(const MathVector<dim,int>& ind) const
    1176              :                 {
    1177              :                         check_multi_index(ind);
    1178          275 :                         for(size_t i=0; i<nsh; ++i)
    1179          275 :                                 if(multi_index(i) == ind) return i;
    1180            0 :                         UG_THROW("Index not found in LagrangeLSFS");
    1181              :                 }
    1182              : 
    1183              :         ///     return the index for a multi_index
    1184            0 :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
    1185              :                 {
    1186              :                         check_multi_index(ind);
    1187              : 
    1188              :                 //      add x range
    1189            0 :                         size_t res = ind[0];
    1190              : 
    1191              :                 //      add y range
    1192            0 :                         for(int i = 0; i < ind[1]; ++i)
    1193            0 :                                 res += (p+1-ind[2]-i);
    1194              : 
    1195              :                 //      add z range
    1196            0 :                         for(int i2 = 0; i2 < ind[2]; ++i2)
    1197            0 :                                 res += BinomCoeff(p+2-i2, p-i2);
    1198              : 
    1199              :                         check_index(res);
    1200            0 :                         return res;
    1201              :                 }
    1202              : 
    1203              :         ///     return the multi_index for an index
    1204            0 :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
    1205              :                 {
    1206              :                         check_index(i);
    1207              : 
    1208            0 :                         int i0 = i, i1 = 0, i2 = 0;
    1209            0 :                         for(i2 = 0; i2 <= (int)p; ++i2)
    1210              :                         {
    1211            0 :                                 const int binom = BinomCoeff(p+2-i2, p-i2);
    1212              : 
    1213              :                                 // if i2 is correct
    1214            0 :                                 const int diff = i0 - binom;
    1215            0 :                                 if(diff < 0)
    1216              :                                 {
    1217            0 :                                         for(i1 = 0; i1 <= (int)p; ++i1)
    1218              :                                         {
    1219              :                                                 // if i1 is correct return values
    1220            0 :                                                 const int diff =  i0 - (p+1-i2-i1);
    1221            0 :                                                 if(diff < 0)
    1222              :                                                         return MathVector<dim,int>( i0, i1, i2);
    1223              : 
    1224              :                                                 // else decrease i1
    1225              :                                                 i0 = diff;
    1226              :                                         }
    1227              :                                 }
    1228              :                                 // else go one level lower
    1229              :                                 else
    1230              :                                         i0 = diff;
    1231              :                         }
    1232              : 
    1233              :                         UG_ASSERT(i0 >= 0, "i0 is negative ("<<i0<<")");
    1234              :                         UG_ASSERT(i1 >= 0, "i1 is negative ("<<i1<<")");
    1235              :                         UG_ASSERT(i2 >= 0, "i1 is negative ("<<i2<<")");
    1236              : 
    1237              :                         UG_ASSERT(0, "Should not reach this line.");
    1238              :                         return MathVector<dim,int>( i0, i1, i2);
    1239              :                 }
    1240              : 
    1241              :         ///     checks in debug mode that index is valid
    1242            0 :                 inline void check_index(size_t i) const
    1243              :                 {
    1244              :                         UG_ASSERT(i < nsh, "Wrong index.");
    1245            0 :                 }
    1246              : 
    1247              :         ///     checks in debug mode that multi-index is valid
    1248            0 :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
    1249              :                 {
    1250              :                         UG_ASSERT(ind[0] <= (int)p && ind[0] >= 0, "Wrong Multiindex.");
    1251              :                         UG_ASSERT(ind[1] <= (int)p && ind[1] >= 0, "Wrong Multiindex.");
    1252              :                         UG_ASSERT(ind[2] <= (int)p && ind[2] >= 0, "Wrong Multiindex.");
    1253              :                         UG_ASSERT(ind[0] + ind[1] + ind[2] <= (int)p, "Wrong Multiindex.");
    1254            0 :                 }
    1255              : 
    1256              :         private:
    1257              :                 Polynomial1D m_vPolynom[p+1];
    1258              :                 Polynomial1D m_vDPolynom[p+1];
    1259              : 
    1260              :                 MathVector<dim,int> m_vMultiIndex[nsh];
    1261              : };
    1262              : 
    1263              : 
    1264              : template <>
    1265              : class FlexLagrangeLSFS<ReferenceTetrahedron>
    1266              :         : public LagrangeLDS<ReferenceTetrahedron>,
    1267              :           public BaseLSFS<FlexLagrangeLSFS<ReferenceTetrahedron>, 3>
    1268              : {
    1269              :         public:
    1270              :         ///     Dimension, where shape functions are defined
    1271              :                 static const int dim = ReferenceTetrahedron::dim;
    1272              : 
    1273              :         public:
    1274              :         ///     default Constructor
    1275            0 :                 FlexLagrangeLSFS() {set_order(1);}
    1276              : 
    1277              :         ///     Constructor
    1278            0 :                 FlexLagrangeLSFS(size_t order) {set_order(order);}
    1279              : 
    1280              :         ///     sets the order
    1281              :                 void set_order(size_t order);
    1282              : 
    1283              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
    1284              :                 inline bool continuous() const {return true;}
    1285              : 
    1286              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
    1287            0 :                 inline size_t num_sh() const {return nsh;}
    1288              : 
    1289              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
    1290              :                 inline bool position(size_t i, MathVector<dim>& pos) const
    1291              :                 {
    1292              :                 //      get Multi Index
    1293              :                         MathVector<dim,int> ind = multi_index(i);
    1294              : 
    1295              :                 //      set position
    1296            0 :                         for(int d = 0; d < dim; ++d)
    1297            0 :                                 pos[d] = TruncatedEquidistantLagrange1D::position(ind[d], p);
    1298              : 
    1299              :                         return true;
    1300              :                 }
    1301              : 
    1302              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
    1303              :                 inline number shape(const size_t i, const MathVector<dim>& x) const
    1304              :                 {
    1305              :                 //      forward
    1306            0 :                         return shape(multi_index(i), x);
    1307              :                 }
    1308              : 
    1309              :         ///     shape value for a Multi Index
    1310            0 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
    1311              :                 {
    1312              :                         check_multi_index(ind);
    1313              :                         //ReferenceTetrahedron::check_position(x);
    1314              : 
    1315              :                 //      get adjoint barycentric index
    1316            0 :                         const size_t i0 = p - ind[0] - ind[1] - ind[2];
    1317            0 :                         const number x0 = 1.0 - x[0] - x[1] - x[2];
    1318              : 
    1319              :                         return    m_vPolynom[ ind[0] ].value(x[0])
    1320            0 :                                         * m_vPolynom[ ind[1] ].value(x[1])
    1321            0 :                                         * m_vPolynom[ ind[2] ].value(x[2])
    1322            0 :                                         * m_vPolynom[ i0 ].value(x0);
    1323              :                 }
    1324              : 
    1325              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
    1326            0 :                 inline void grad(grad_type& g, const size_t i, const MathVector<dim>& x) const
    1327              :                 {
    1328            0 :                         grad(g, multi_index(i), x);
    1329            0 :                 }
    1330              : 
    1331              :         ///     evaluates the gradient
    1332            0 :                 inline void grad(grad_type& g, const MathVector<dim,int> ind,
    1333              :                                                             const MathVector<dim>& x) const
    1334              :                 {
    1335              :                         check_multi_index(ind);
    1336              :                         //ReferenceTetrahedron::check_position(x);
    1337              : 
    1338              :                 //      get adjoint barycentric index and position
    1339            0 :                         const size_t i0 = p - ind[0] - ind[1] - ind[2];
    1340            0 :                         const number x0 = 1 - x[0] - x[1] - x[2];
    1341              : 
    1342              :                         UG_ASSERT(i0 <= p, "Wrong Multiindex.");
    1343              :                         UG_ASSERT(x0 <= 1.0+SMALL && x0 >= -SMALL, "Wrong Position.");
    1344              : 
    1345              :                 //      loop dimensions
    1346            0 :                         for(int d = 0; d < dim; ++d)
    1347              :                         {
    1348            0 :                                 g[d] = m_vDPolynom[ind[d]].value(x[d])
    1349            0 :                                                 * m_vPolynom[i0].value(x0);
    1350            0 :                                 g[d] += (-1) * m_vDPolynom[i0].value(x0)
    1351            0 :                                                    * m_vPolynom[ind[d]].value(x[d]);
    1352              : 
    1353              :                         //      multiply by all functions not depending on x[d]
    1354            0 :                                 for(int d2 = 0; d2 < dim; ++d2)
    1355              :                                 {
    1356              :                                 //      skip own value
    1357            0 :                                         if(d2 == d) continue;
    1358              : 
    1359            0 :                                         g[d] *= m_vPolynom[ind[d2]].value(x[d2]);
    1360              :                                 }
    1361              :                         }
    1362            0 :                 }
    1363              : 
    1364              :         ///     return Multi index for index i
    1365              :                 inline const MathVector<dim,int>& multi_index(size_t i) const
    1366              :                 {
    1367              :                         check_index(i);
    1368              :                         return m_vMultiIndex[i];
    1369              :                 }
    1370              : 
    1371              :         ///     return the index for a multi_index
    1372            0 :                 inline size_t index(const MathVector<dim,int>& ind) const
    1373              :                 {
    1374              :                         check_multi_index(ind);
    1375            0 :                         for(size_t i=0; i<nsh; ++i)
    1376            0 :                                 if(multi_index(i) == ind) return i;
    1377            0 :                         UG_THROW("Index not found in LagrangeLSFS");
    1378              :                 }
    1379              : 
    1380              :         ///     return the index for a multi_index
    1381              :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
    1382              :                 {
    1383              :                         check_multi_index(ind);
    1384              : 
    1385              :                 //      add x range
    1386              :                         size_t res = ind[0];
    1387              : 
    1388              :                 //      add y range
    1389              :                         for(int i = 0; i < ind[1]; ++i)
    1390              :                                 res += (p+1-ind[2]-i);
    1391              : 
    1392              :                 //      add z range
    1393              :                         for(int i2 = 0; i2 < ind[2]; ++i2)
    1394              :                                 res += BinomCoeff(p+2-i2, p-i2);
    1395              : 
    1396              :                         check_index(res);
    1397              :                         return res;
    1398              :                 }
    1399              : 
    1400              :         ///     return the multi_index for an index
    1401              :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
    1402              :                 {
    1403              :                         check_index(i);
    1404              : 
    1405              :                         int i0 = i, i1 = 0, i2 = 0;
    1406              :                         for(i2 = 0; i2 <= (int)p; ++i2)
    1407              :                         {
    1408              :                                 const int binom = BinomCoeff(p+2-i2, p-i2);
    1409              : 
    1410              :                                 // if i2 is correct
    1411              :                                 const int diff = i0 - binom;
    1412              :                                 if(diff < 0)
    1413              :                                 {
    1414              :                                         for(i1 = 0; i1 <= (int)p; ++i1)
    1415              :                                         {
    1416              :                                                 // if i1 is correct return values
    1417              :                                                 const int diff =  i0 - (p+1-i2-i1);
    1418              :                                                 if(diff < 0)
    1419              :                                                         return MathVector<dim,int>( i0, i1, i2);
    1420              : 
    1421              :                                                 // else decrease i1
    1422              :                                                 i0 = diff;
    1423              :                                         }
    1424              :                                 }
    1425              :                                 // else go one level lower
    1426              :                                 else
    1427              :                                         i0 = diff;
    1428              :                         }
    1429              : 
    1430              :                         UG_ASSERT(i0 >= 0, "i0 is negative ("<<i0<<")");
    1431              :                         UG_ASSERT(i1 >= 0, "i1 is negative ("<<i1<<")");
    1432              :                         UG_ASSERT(i2 >= 0, "i1 is negative ("<<i2<<")");
    1433              : 
    1434              :                         UG_ASSERT(0, "Should not reach this line.");
    1435              :                         return MathVector<dim,int>( i0, i1, i2);
    1436              :                 }
    1437              : 
    1438              :         ///     checks in debug mode that index is valid
    1439              :                 inline void check_index(size_t i) const
    1440              :                 {
    1441              :                         UG_ASSERT(i < nsh, "Wrong index.");
    1442              :                 }
    1443              : 
    1444              :         ///     checks in debug mode that multi-index is valid
    1445              :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
    1446              :                 {
    1447              :                         UG_ASSERT(ind[0] <= (int)p && ind[0] >= 0, "Wrong Multiindex.");
    1448              :                         UG_ASSERT(ind[1] <= (int)p && ind[1] >= 0, "Wrong Multiindex.");
    1449              :                         UG_ASSERT(ind[2] <= (int)p && ind[2] >= 0, "Wrong Multiindex.");
    1450              :                         UG_ASSERT(ind[0] + ind[1] + ind[2] <= (int)p, "Wrong Multiindex.");
    1451              :                 }
    1452              : 
    1453              :         private:
    1454              :         ///     order
    1455              :                 size_t p;
    1456              : 
    1457              :         /// Number of shape functions
    1458              :                 size_t nsh;
    1459              : 
    1460              :                 std::vector<Polynomial1D> m_vPolynom;     ///< Shape Polynomials
    1461              :                 std::vector<Polynomial1D> m_vDPolynom;    ///< Derivative of Shape Polynomial
    1462              : 
    1463              :                 std::vector<MathVector<dim,int> > m_vMultiIndex;
    1464              : };
    1465              : 
    1466              : ///////////////////////////////////////////////////////////////////////////////
    1467              : // Prism
    1468              : ///////////////////////////////////////////////////////////////////////////////
    1469              : 
    1470              : template <int TOrder>
    1471              : class LagrangeLSFS<ReferencePrism, TOrder>
    1472              :         : public LagrangeLDS<ReferencePrism>,
    1473              :           public BaseLSFS<LagrangeLSFS<ReferencePrism, TOrder>, 3>
    1474              : {
    1475              :         private:
    1476              :         ///     abbreviation for order
    1477              :                 static const size_t p = TOrder;
    1478              : 
    1479              :         /// dofs per layer
    1480              :                 static const size_t dofPerLayer = BinomialCoefficient<2 + p, p>::value;
    1481              : 
    1482              :         ///     base class
    1483              :                 typedef BaseLSFS<LagrangeLSFS<ReferencePrism, TOrder>, 3> base_type;
    1484              : 
    1485              :         public:
    1486              :         ///     Shape type
    1487              :                 typedef typename base_type::shape_type shape_type;
    1488              : 
    1489              :         ///     Gradient type
    1490              :                 typedef typename base_type::grad_type grad_type;
    1491              : 
    1492              :         public:
    1493              :         ///     Order of Shape functions
    1494              :                 static const size_t order = TOrder;
    1495              : 
    1496              :         ///     Dimension, where shape functions are defined
    1497              :                 static const int dim = ReferencePrism::dim;
    1498              : 
    1499              :         /// Number of shape functions
    1500              :                 static const size_t nsh = dofPerLayer*(p+1);
    1501              : 
    1502              :         public:
    1503              :         ///     Constructor
    1504              :                 LagrangeLSFS();
    1505              : 
    1506              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
    1507            0 :                 inline bool continuous() const {return true;}
    1508              : 
    1509              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
    1510         4020 :                 inline size_t num_sh() const {return nsh;}
    1511              : 
    1512              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
    1513            0 :                 inline bool position(size_t i, MathVector<dim>& pos) const
    1514              :                 {
    1515              :                 //      get Multi Index
    1516              :                         MathVector<dim,int> ind = multi_index(i);
    1517              : 
    1518              :                 //      set position
    1519          402 :                         for(int d = 0; d < 2; ++d)
    1520          268 :                                 pos[d] = TruncatedEquidistantLagrange1D::position(ind[d], p);
    1521              : 
    1522          134 :                         pos[2] = EquidistantLagrange1D::position(ind[2], p);
    1523              : 
    1524            0 :                         return true;
    1525              :                 }
    1526              : 
    1527              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
    1528            0 :                 inline number shape(const size_t i, const MathVector<dim>& x) const
    1529              :                 {
    1530              :                 //      forward
    1531         9040 :                         return shape(multi_index(i), x);
    1532              :                 }
    1533              : 
    1534              :         ///     shape value for a Multi Index
    1535         9040 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
    1536              :                 {
    1537              :                         check_multi_index(ind);
    1538              :                         //ReferencePrism::check_position(x);
    1539              : 
    1540              :                 //      get adjoint barycentric index
    1541         9040 :                         const size_t i0 = p - ind[0] - ind[1];
    1542         9040 :                         const number x0 = 1.0 - x[0] - x[1];
    1543              : 
    1544              :                                 //      x-y direction
    1545         9040 :                         return    m_vTruncPolynom[ ind[0] ].value(x[0])
    1546         9040 :                                         * m_vTruncPolynom[ ind[1] ].value(x[1])
    1547         9040 :                                         * m_vTruncPolynom[   i0   ].value( x0 )
    1548              :                                 //      z direction
    1549         9040 :                                         * m_vPolynom[ ind[2] ].value(x[2]);
    1550              :                 }
    1551              : 
    1552              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
    1553         2560 :                 void grad(grad_type& g, const size_t i, const MathVector<dim>& x) const
    1554              :                 {
    1555         2560 :                         grad(g, multi_index(i), x);
    1556         2560 :                 }
    1557              : 
    1558              :         ///     evaluates the gradient
    1559         2560 :                 void grad(grad_type& g, const MathVector<dim,int> ind,
    1560              :                                                                 const MathVector<dim>& x) const
    1561              :                 {
    1562              :                         check_multi_index(ind);
    1563              :                         //ReferencePrism::check_position(x);
    1564              : 
    1565              :                 //      get adjoint barycentric index and position
    1566         2560 :                         const size_t i0 = p - ind[0] - ind[1];
    1567         2560 :                         const number x0 = 1 - x[0] - x[1];
    1568              : 
    1569              :                         UG_ASSERT(i0 <= p, "Wrong Multiindex.");
    1570              :                         UG_ASSERT(x0 <= 1.0+SMALL && x0 >= -SMALL, "Wrong Position.");
    1571              : 
    1572              :                 //      x-y gradient
    1573         7680 :                         for(size_t d = 0; d < 2; ++d)
    1574              :                         {
    1575         5120 :                                 g[d] = m_vDTruncPolynom[ind[d]].value(x[d])
    1576         5120 :                                                 * m_vTruncPolynom[i0].value(x0);
    1577         5120 :                                 g[d] += (-1) * m_vDTruncPolynom[i0].value(x0)
    1578         5120 :                                                    * m_vTruncPolynom[ind[d]].value(x[d]);
    1579              : 
    1580              :                         //      multiply by all functions not depending on x[d]
    1581        15360 :                                 for(size_t d2 = 0; d2 < 2; ++d2)
    1582              :                                 {
    1583              :                                 //      skip own value
    1584        10240 :                                         if(d2 == d) continue;
    1585              : 
    1586        10240 :                                         g[d] *= m_vTruncPolynom[ind[d2]].value(x[d2]);
    1587              :                                 }
    1588              : 
    1589              :                         //      multiply by z coordinate
    1590        10240 :                                 g[d] *= m_vPolynom[ind[2]].value(x[2]);
    1591              :                         }
    1592              : 
    1593              :                 //      z gradient
    1594         2560 :                         g[2] = m_vDPolynom[ind[2]].value(x[2]);
    1595         2560 :                         g[2] *=   m_vTruncPolynom[ ind[0] ].value(x[0])
    1596         2560 :                                            * m_vTruncPolynom[ ind[1] ].value(x[1])
    1597         2560 :                                            * m_vTruncPolynom[   i0   ].value( x0 );
    1598         2560 :                 }
    1599              : 
    1600              :         ///     return Multi index for index i
    1601            0 :                 inline const MathVector<dim,int>& multi_index(size_t i) const
    1602              :                 {
    1603              :                         check_index(i);
    1604         9046 :                         return m_vMultiIndex[i];
    1605              :                 }
    1606              : 
    1607              :         ///     return the index for a multi_index
    1608           64 :                 inline size_t index(const MathVector<dim,int>& ind) const
    1609              :                 {
    1610              :                         check_multi_index(ind);
    1611         1012 :                         for(size_t i=0; i<nsh; ++i)
    1612         1012 :                                 if(multi_index(i) == ind) return i;
    1613            0 :                         UG_THROW("Index not found in LagrangeLSFS");
    1614              :                 }
    1615              : 
    1616              :         ///     return the index for a multi_index
    1617            0 :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
    1618              :                 {
    1619              :                         check_multi_index(ind);
    1620              : 
    1621            0 :                         size_t res = ind[0];
    1622            0 :                         for(int i = 0; i < ind[1]; ++i)
    1623            0 :                                 res += (p+1-i);
    1624              : 
    1625              :                         // add height
    1626            0 :                         res += ind[2] * dofPerLayer;
    1627              : 
    1628            0 :                         return res;
    1629              :                 }
    1630              : 
    1631              :         ///     return the multi_index for an index
    1632            0 :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
    1633              :                 {
    1634              :                         check_index(i);
    1635              : 
    1636            0 :                         const size_t i2 = i / dofPerLayer;
    1637              : 
    1638            0 :                         int i0 = i - i2*dofPerLayer, i1;
    1639            0 :                         for(i1 = 0; i1 < (int)p; ++i1)
    1640              :                         {
    1641            0 :                                 const int diff = i0 - (p+1-i1);
    1642            0 :                                 if(diff < 0)
    1643              :                                         break;
    1644              :                                 i0 = diff;
    1645              :                         }
    1646              : 
    1647            0 :                         return MathVector<dim,int>( i0, i1, i2);
    1648              :                 }
    1649              : 
    1650              :         ///     checks in debug mode that index is valid
    1651            0 :                 inline void check_index(size_t i) const
    1652              :                 {
    1653              :                         UG_ASSERT(i < nsh, "Wrong index.");
    1654            0 :                 }
    1655              : 
    1656              :         ///     checks in debug mode that multi-index is valid
    1657            0 :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
    1658              :                 {
    1659              :                         UG_ASSERT(ind[0] <= (int)p && ind[0] >= 0, "Wrong Multiindex.");
    1660              :                         UG_ASSERT(ind[1] <= (int)p && ind[1] >= 0, "Wrong Multiindex.");
    1661              :                         UG_ASSERT(ind[0] + ind[1] <= (int)p, "Wrong Multiindex.");
    1662              :                         UG_ASSERT(ind[2] <= (int)p && ind[2] >= 0, "Wrong Multiindex.");
    1663            0 :                 }
    1664              : 
    1665              :         private:
    1666              :                 Polynomial1D m_vPolynom[p+1];
    1667              :                 Polynomial1D m_vDPolynom[p+1];
    1668              :                 Polynomial1D m_vTruncPolynom[p+1];
    1669              :                 Polynomial1D m_vDTruncPolynom[p+1];
    1670              : 
    1671              :                 MathVector<dim,int> m_vMultiIndex[nsh];
    1672              : };
    1673              : 
    1674              : 
    1675              : template <>
    1676              : class FlexLagrangeLSFS<ReferencePrism>
    1677              :         : public LagrangeLDS<ReferencePrism>,
    1678              :           public BaseLSFS<FlexLagrangeLSFS<ReferencePrism>, 3>
    1679              : {
    1680              :         public:
    1681              :         ///     Dimension, where shape functions are defined
    1682              :                 static const int dim = ReferencePrism::dim;
    1683              : 
    1684              :         public:
    1685              :         ///     default Constructor
    1686            0 :                 FlexLagrangeLSFS() {set_order(1);}
    1687              : 
    1688              :         ///     Constructor
    1689            0 :                 FlexLagrangeLSFS(size_t order) {set_order(order);}
    1690              : 
    1691              :         ///     sets the order
    1692              :                 void set_order(size_t order);
    1693              : 
    1694              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
    1695              :                 inline bool continuous() const {return true;}
    1696              : 
    1697              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
    1698            0 :                 inline size_t num_sh() const {return nsh;}
    1699              : 
    1700              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
    1701            0 :                 inline bool position(size_t i, MathVector<dim>& pos) const
    1702              :                 {
    1703              :                 //      get Multi Index
    1704              :                         MathVector<dim,int> ind = multi_index(i);
    1705              : 
    1706              :                 //      set position
    1707            0 :                         for(int d = 0; d < 2; ++d)
    1708            0 :                                 pos[d] = TruncatedEquidistantLagrange1D::position(ind[d], p);
    1709              : 
    1710            0 :                         pos[2] = EquidistantLagrange1D::position(ind[2], p);
    1711              : 
    1712            0 :                         return true;
    1713              :                 }
    1714              : 
    1715              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
    1716              :                 inline number shape(const size_t i, const MathVector<dim>& x) const
    1717              :                 {
    1718              :                 //      forward
    1719            0 :                         return shape(multi_index(i), x);
    1720              :                 }
    1721              : 
    1722              :         ///     shape value for a Multi Index
    1723            0 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
    1724              :                 {
    1725              :                         check_multi_index(ind);
    1726              :                         //ReferencePrism::check_position(x);
    1727              : 
    1728              :                 //      get adjoint barycentric index
    1729            0 :                         const size_t i0 = p - ind[0] - ind[1];
    1730            0 :                         const number x0 = 1.0 - x[0] - x[1];
    1731              : 
    1732              :                                 //      x-y direction
    1733              :                         return    m_vTruncPolynom[ ind[0] ].value(x[0])
    1734            0 :                                         * m_vTruncPolynom[ ind[1] ].value(x[1])
    1735            0 :                                         * m_vTruncPolynom[   i0   ].value( x0 )
    1736              :                                 //      z direction
    1737            0 :                                         * m_vPolynom[ ind[2] ].value(x[2]);
    1738              :                 }
    1739              : 
    1740              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
    1741            0 :                 void grad(grad_type& g, const size_t i, const MathVector<dim>& x) const
    1742              :                 {
    1743            0 :                         grad(g, multi_index(i), x);
    1744            0 :                 }
    1745              : 
    1746              :         ///     evaluates the gradient
    1747            0 :                 void grad(grad_type& g, const MathVector<dim,int> ind,
    1748              :                                                                 const MathVector<dim>& x) const
    1749              :                 {
    1750              :                         check_multi_index(ind);
    1751              :                         //ReferencePrism::check_position(x);
    1752              : 
    1753              :                 //      get adjoint barycentric index and position
    1754            0 :                         const size_t i0 = p - ind[0] - ind[1];
    1755            0 :                         const number x0 = 1 - x[0] - x[1];
    1756              : 
    1757              :                         UG_ASSERT(i0 <= p, "Wrong Multiindex.");
    1758              :                         UG_ASSERT(x0 <= 1.0+SMALL && x0 >= -SMALL, "Wrong Position.");
    1759              : 
    1760              :                 //      x-y gradient
    1761            0 :                         for(size_t d = 0; d < 2; ++d)
    1762              :                         {
    1763            0 :                                 g[d] = m_vDTruncPolynom[ind[d]].value(x[d])
    1764            0 :                                                 * m_vTruncPolynom[i0].value(x0);
    1765            0 :                                 g[d] += (-1) * m_vDTruncPolynom[i0].value(x0)
    1766            0 :                                                    * m_vTruncPolynom[ind[d]].value(x[d]);
    1767              : 
    1768              :                         //      multiply by all functions not depending on x[d]
    1769            0 :                                 for(size_t d2 = 0; d2 < 2; ++d2)
    1770              :                                 {
    1771              :                                 //      skip own value
    1772            0 :                                         if(d2 == d) continue;
    1773              : 
    1774            0 :                                         g[d] *= m_vTruncPolynom[ind[d2]].value(x[d2]);
    1775              :                                 }
    1776              : 
    1777              :                         //      multiply by z coordinate
    1778            0 :                                 g[d] *= m_vPolynom[ind[2]].value(x[2]);
    1779              :                         }
    1780              : 
    1781              :                 //      z gradient
    1782            0 :                         g[2] = m_vDPolynom[ind[2]].value(x[2]);
    1783            0 :                         g[2] *=   m_vTruncPolynom[ ind[0] ].value(x[0])
    1784            0 :                                            * m_vTruncPolynom[ ind[1] ].value(x[1])
    1785            0 :                                            * m_vTruncPolynom[   i0   ].value( x0 );
    1786            0 :                 }
    1787              : 
    1788              :         ///     return Multi index for index i
    1789              :                 inline const MathVector<dim,int>& multi_index(size_t i) const
    1790              :                 {
    1791              :                         check_index(i);
    1792              :                         return m_vMultiIndex[i];
    1793              :                 }
    1794              : 
    1795              :         ///     return the index for a multi_index
    1796            0 :                 inline size_t index(const MathVector<dim,int>& ind) const
    1797              :                 {
    1798              :                         check_multi_index(ind);
    1799            0 :                         for(size_t i=0; i<nsh; ++i)
    1800            0 :                                 if(multi_index(i) == ind) return i;
    1801            0 :                         UG_THROW("Index not found in LagrangeLSFS");
    1802              :                 }
    1803              : 
    1804              :         ///     return the index for a multi_index
    1805              :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
    1806              :                 {
    1807              :                         check_multi_index(ind);
    1808              : 
    1809              :                         size_t res = ind[0];
    1810              :                         for(int i = 0; i < ind[1]; ++i)
    1811              :                                 res += (p+1-i);
    1812              : 
    1813              :                         // add height
    1814              :                         res += ind[2] * dofPerLayer;
    1815              : 
    1816              :                         return res;
    1817              :                 }
    1818              : 
    1819              :         ///     return the multi_index for an index
    1820              :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
    1821              :                 {
    1822              :                         check_index(i);
    1823              : 
    1824              :                         const size_t i2 = i / dofPerLayer;
    1825              : 
    1826              :                         int i0 = i - i2*dofPerLayer, i1;
    1827              :                         for(i1 = 0; i1 < (int)p; ++i1)
    1828              :                         {
    1829              :                                 const int diff = i0 - (p+1-i1);
    1830              :                                 if(diff < 0)
    1831              :                                         break;
    1832              :                                 i0 = diff;
    1833              :                         }
    1834              : 
    1835              :                         return MathVector<dim,int>( i0, i1, i2);
    1836              :                 }
    1837              : 
    1838              :         ///     checks in debug mode that index is valid
    1839              :                 inline void check_index(size_t i) const
    1840              :                 {
    1841              :                         UG_ASSERT(i < nsh, "Wrong index.");
    1842              :                 }
    1843              : 
    1844              :         ///     checks in debug mode that multi-index is valid
    1845              :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
    1846              :                 {
    1847              :                         UG_ASSERT(ind[0] <= (int)p && ind[0] >= 0, "Wrong Multiindex.");
    1848              :                         UG_ASSERT(ind[1] <= (int)p && ind[1] >= 0, "Wrong Multiindex.");
    1849              :                         UG_ASSERT(ind[0] + ind[1] <= (int)p, "Wrong Multiindex.");
    1850              :                         UG_ASSERT(ind[2] <= (int)p && ind[2] >= 0, "Wrong Multiindex.");
    1851              :                 }
    1852              : 
    1853              :         private:
    1854              :         ///     order
    1855              :                 size_t p;
    1856              : 
    1857              :         /// Number of shape functions
    1858              :                 size_t nsh;
    1859              : 
    1860              :         ///     number of dofs per layer
    1861              :                 size_t dofPerLayer;
    1862              : 
    1863              :                 std::vector<Polynomial1D> m_vPolynom;
    1864              :                 std::vector<Polynomial1D> m_vDPolynom;
    1865              :                 std::vector<Polynomial1D> m_vTruncPolynom;
    1866              :                 std::vector<Polynomial1D> m_vDTruncPolynom;
    1867              : 
    1868              :                 std::vector<MathVector<dim,int> > m_vMultiIndex;
    1869              : };
    1870              : 
    1871              : ///////////////////////////////////////////////////////////////////////////////
    1872              : // Pyramid
    1873              : ///////////////////////////////////////////////////////////////////////////////
    1874              : 
    1875              : namespace {
    1876              : template <int p>
    1877              : struct NumberOfDoFsOfPyramid{
    1878              :         enum{value = NumberOfDoFsOfPyramid<p-1>::value + (p+1)*(p+1)};
    1879              : };
    1880              : 
    1881              : // specialization to end recursion
    1882              : template <> struct NumberOfDoFsOfPyramid<1>{enum {value = 5};};
    1883              : template <> struct NumberOfDoFsOfPyramid<0>{enum {value = 0};};
    1884              : template <> struct NumberOfDoFsOfPyramid<-1>{enum {value = 0};};
    1885              : } // end empty namespace
    1886              : 
    1887              : // todo: Implement higher order (impossible ?)
    1888              : //      NOTE:   Currently only 1st order is implemented. There is no shape function
    1889              : //                      set for pyramids, that is continuous and allows a continuous
    1890              : //                      derivative in the inner of the pyramid. This is basically, since
    1891              : //                      one regards the pyramid as two tetrahedrons, glued together.
    1892              : template <int TOrder>
    1893              : class LagrangeLSFS<ReferencePyramid, TOrder>
    1894              :         : public LagrangeLDS<ReferencePyramid>,
    1895              :           public BaseLSFS<LagrangeLSFS<ReferencePyramid, TOrder>, 3>
    1896              : {
    1897              :         private:
    1898              :         ///     abbreviation for order
    1899              :                 static const size_t p = TOrder;
    1900              : 
    1901              :         ///     base class
    1902              :                 typedef BaseLSFS<LagrangeLSFS<ReferencePyramid, TOrder>, 3> base_type;
    1903              : 
    1904              :         public:
    1905              :         ///     Shape type
    1906              :                 typedef typename base_type::shape_type shape_type;
    1907              : 
    1908              :         ///     Gradient type
    1909              :                 typedef typename base_type::grad_type grad_type;
    1910              : 
    1911              :         public:
    1912              :         ///     Order of Shape functions
    1913              :                 static const size_t order = TOrder;
    1914              : 
    1915              :         ///     Dimension, where shape functions are defined
    1916              :                 static const int dim = 3;       //reference_element_type::dim; (compile error on OSX 10.5)
    1917              : 
    1918              :         /// Number of shape functions
    1919              :                 static const size_t nsh = NumberOfDoFsOfPyramid<p>::value;
    1920              : 
    1921              :         public:
    1922              :         ///     Constructor
    1923              :                 LagrangeLSFS();
    1924              : 
    1925              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
    1926            0 :                 inline bool continuous() const {return true;}
    1927              : 
    1928              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
    1929          360 :                 inline size_t num_sh() const {return nsh;}
    1930              : 
    1931              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
    1932            0 :                 inline bool position(size_t i, MathVector<dim>& pos) const
    1933              :                 {
    1934              :                 //      get Multi Index
    1935              :                         MathVector<dim,int> ind = multi_index(i);
    1936              : 
    1937              :                 //      set position
    1938           60 :                         for(int d = 0; d < dim; ++d)
    1939           45 :                                 pos[d] = EquidistantLagrange1D::position(ind[d], p);
    1940              : 
    1941            0 :                         return true;
    1942              :                 }
    1943              : 
    1944              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
    1945          450 :                 inline number shape(const size_t i, const MathVector<dim>& x) const
    1946              :                 {
    1947              :                 //      only first order
    1948            0 :                         if(p != 1) UG_THROW("Only 1. order Lagrange Pyramid implemented.");
    1949              : 
    1950              :                 //      smaller value of x and y
    1951          450 :                         number m = x[0];
    1952          450 :                         if (x[0] > x[1]) m = x[1];
    1953              : 
    1954          450 :                         switch(i)
    1955              :                         {
    1956           90 :                           case 0 : return((1.0-x[0])*(1.0-x[1]) + x[2]*(m-1.0));
    1957           90 :                           case 1 : return(x[0]*(1.0-x[1])       - x[2]*m);
    1958           90 :                           case 2 : return(x[0]*x[1]             + x[2]*m);
    1959           90 :                           case 3 : return((1.0-x[0])*x[1]       - x[2]*m);
    1960           90 :                           case 4 : return(x[2]);
    1961            0 :                           default: UG_THROW("Wrong index "<< i<<" in Pyramid");
    1962              :                         }
    1963              :                 }
    1964              : 
    1965              :         ///     shape value for a Multi Index
    1966            0 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
    1967              :                 {
    1968              :                         check_multi_index(ind);
    1969              :                         //ReferencePyramid::check_position(x);
    1970              : 
    1971              :                 //      forward
    1972            0 :                         return shape(index(ind), x);
    1973              :                 }
    1974              : 
    1975              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
    1976          200 :                 inline void grad(grad_type& g, const size_t i, const MathVector<dim>& x) const
    1977              :                 {
    1978              :                 //      only first order
    1979            0 :                         if(p != 1) UG_THROW("Only 1. order Lagrange Pyramid implemented.");
    1980              : 
    1981              :                         int m = 0;
    1982          200 :                         if (x[0] > x[1]) m = 1;
    1983              : 
    1984          200 :                         switch(i)
    1985              :                         {
    1986              :                           case 0:
    1987           40 :                                 g[0] = -(1.0-x[1]);
    1988           40 :                                 g[1] = -(1.0-x[0]) + x[2];
    1989           40 :                                 g[2] = -(1.0-x[1]);
    1990           40 :                                 g[m] += x[2];
    1991           40 :                                 break;
    1992              :                           case 1:
    1993           40 :                                 g[0] = (1.0-x[1]);
    1994           40 :                                 g[1] = -x[0];
    1995           40 :                                 g[2] = -x[1];
    1996           40 :                                 g[m] -= x[2];
    1997           40 :                                 break;
    1998              :                           case 2:
    1999           40 :                                 g[0] = x[1];
    2000           40 :                                 g[1] = x[0];
    2001           40 :                                 g[2] = x[1];
    2002           40 :                                 g[m] += x[2];
    2003           40 :                                 break;
    2004              :                           case 3:
    2005           40 :                                 g[0] = -x[1];
    2006           40 :                                 g[1] = 1.0-x[0];
    2007           40 :                                 g[2] = -x[1];
    2008           40 :                                 g[m] -= x[2];
    2009           40 :                                 break;
    2010              :                       case 4:
    2011           40 :                                 g[0] = 0.0;
    2012           40 :                                 g[1] = 0.0;
    2013           40 :                                 g[2] = 1.0;
    2014           40 :                                 break;
    2015            0 :                       default: UG_THROW("Wrong index "<< i<<" in Pyramid");
    2016              :                         }
    2017              : 
    2018          200 :                 }
    2019              : 
    2020              :         ///     evaluates the gradient
    2021            0 :                 inline void grad(grad_type& g, const MathVector<dim,int> ind,
    2022              :                                                                    const MathVector<dim>& x) const
    2023              :                 {
    2024            0 :                         grad(g, index(ind), x);
    2025            0 :                 }
    2026              : 
    2027              :         ///     return Multi index for index i
    2028            0 :                 inline const MathVector<dim,int>& multi_index(size_t i) const
    2029              :                 {
    2030              :                         check_index(i);
    2031            5 :                         return m_vMultiIndex[i];
    2032              :                 }
    2033              : 
    2034              :         ///     return the index for a multi_index
    2035            5 :                 inline size_t index(const MathVector<dim,int>& ind) const
    2036              :                 {
    2037              :                         check_multi_index(ind);
    2038           15 :                         for(size_t i=0; i<nsh; ++i)
    2039           15 :                                 if(multi_index(i) == ind) return i;
    2040            0 :                         UG_THROW("Index not found in LagrangeLSFS");
    2041              :                 }
    2042              : 
    2043              :         ///     return the index for a multi_index
    2044            0 :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
    2045              :                 {
    2046              :                         check_multi_index(ind);
    2047              : 
    2048              :                         size_t res = 0;
    2049              : 
    2050              :                 //      add layers that are completely filled
    2051            0 :                         for(int i2 = 0; i2 < ind[2]; ++i2)
    2052            0 :                                 res += (p+1-i2)*(p+1-i2);
    2053              : 
    2054              :                 //      add dofs of top z-layer
    2055            0 :                         res += ind[1] * (p+1-ind[2]) + ind[0];
    2056              : 
    2057              :                         check_index(res);
    2058            0 :                         return res;
    2059              :                 }
    2060              : 
    2061              :         ///     return the multi_index for an index
    2062            0 :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
    2063              :                 {
    2064              :                         check_index(i);
    2065              : 
    2066              :                 //      get z layer
    2067            0 :                         int iTmp = i;
    2068              :                         int i2;
    2069            0 :                         for(i2 = 0; i2 < (int)p; ++i2)
    2070              :                         {
    2071            0 :                                 const int diff = iTmp - (p+1-i2)*(p+1-i2);
    2072            0 :                                 if(diff < 0) break;
    2073              : 
    2074              :                                 iTmp = diff;
    2075              :                         }
    2076              : 
    2077            0 :                         return MathVector<dim,int>( iTmp%(p+1-i2), iTmp/(p+1-i2), i2);
    2078              :                 }
    2079              : 
    2080              :         ///     checks in debug mode that index is valid
    2081            0 :                 inline void check_index(size_t i) const
    2082              :                 {
    2083              :                         UG_ASSERT(i < nsh, "Wrong index.");
    2084            0 :                 }
    2085              : 
    2086              :         ///     checks in debug mode that multi-index is valid
    2087            0 :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
    2088              :                 {
    2089              :                         UG_ASSERT(ind[0] <= (int)p-ind[2] && ind[0] >= 0, "Wrong Multiindex.");
    2090              :                         UG_ASSERT(ind[1] <= (int)p-ind[2] && ind[1] >= 0, "Wrong Multiindex.");
    2091              :                         UG_ASSERT(ind[2] <= (int)p && ind[2] >= 0, "Wrong Multiindex.");
    2092            0 :                 }
    2093              : 
    2094              :         private:
    2095              :                 std::vector<std::vector<Polynomial1D> > m_vvPolynom;
    2096              :                 std::vector<std::vector<Polynomial1D> > m_vvDPolynom;
    2097              : 
    2098              :                 MathVector<dim,int> m_vMultiIndex[nsh];
    2099              : };
    2100              : 
    2101              : ///////////////////////////////////////////////////////////////////////////////
    2102              : // Hexahedron
    2103              : ///////////////////////////////////////////////////////////////////////////////
    2104              : 
    2105              : template <int TOrder>
    2106              : class LagrangeLSFS<ReferenceHexahedron, TOrder>
    2107              :         : public LagrangeLDS<ReferenceHexahedron>,
    2108              :           public BaseLSFS<LagrangeLSFS<ReferenceHexahedron, TOrder>, 3>
    2109              : {
    2110              :         private:
    2111              :         ///     abbreviation for order
    2112              :                 static const size_t p = TOrder;
    2113              : 
    2114              :         ///     base class
    2115              :                 typedef BaseLSFS<LagrangeLSFS<ReferenceHexahedron, TOrder>, 3> base_type;
    2116              : 
    2117              :         public:
    2118              :         ///     Shape type
    2119              :                 typedef typename base_type::shape_type shape_type;
    2120              : 
    2121              :         ///     Gradient type
    2122              :                 typedef typename base_type::grad_type grad_type;
    2123              : 
    2124              :         public:
    2125              :         ///     Order of Shape functions
    2126              :                 static const size_t order = TOrder;
    2127              : 
    2128              :         ///     Dimension, where shape functions are defined
    2129              :                 static const int dim = ReferenceHexahedron::dim;
    2130              : 
    2131              :         /// Number of shape functions
    2132              :                 static const size_t nsh = (p+1)*(p+1)*(p+1);
    2133              : 
    2134              :         public:
    2135              :         ///     Constructor
    2136              :                 LagrangeLSFS();
    2137              : 
    2138              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
    2139            0 :                 inline bool continuous() const {return true;}
    2140              : 
    2141              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
    2142         6120 :                 inline size_t num_sh() const {return nsh;}
    2143              : 
    2144              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
    2145            0 :                 inline bool position(size_t i, MathVector<dim>& pos) const
    2146              :                 {
    2147              :                 //      get Multi Index
    2148              :                         MathVector<dim,int> ind = multi_index(i);
    2149              : 
    2150              :                 //      set position
    2151          824 :                         for(int d = 0; d < dim; ++d)
    2152          618 :                                 pos[d] = EquidistantLagrange1D::position(ind[d], p);
    2153              : 
    2154            0 :                         return true;
    2155              :                 }
    2156              : 
    2157              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
    2158            0 :                 inline number shape(const size_t i, const MathVector<dim>& x) const
    2159              :                 {
    2160              :                 //      forward
    2161        17698 :                         return shape(multi_index(i), x);
    2162              :                 }
    2163              : 
    2164              :         ///     shape value for a Multi Index
    2165        17698 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
    2166              :                 {
    2167              :                         check_multi_index(ind);
    2168              :                         //ReferenceHexahedron::check_position(x);
    2169              : 
    2170        17698 :                         return    m_vPolynom[ ind[0] ].value(x[0])
    2171        17698 :                                         * m_vPolynom[ ind[1] ].value(x[1])
    2172        17698 :                                         * m_vPolynom[ ind[2] ].value(x[2]);
    2173              :                 }
    2174              : 
    2175              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
    2176         3960 :                 inline void grad(grad_type& g, const size_t i, const MathVector<dim>& x) const
    2177              :                 {
    2178         3960 :                         grad(g, multi_index(i), x);
    2179         3960 :                 }
    2180              : 
    2181              :         ///     evaluates the gradient
    2182         3960 :                 inline void grad(grad_type& g, const MathVector<dim,int> ind,
    2183              :                                                         const MathVector<dim>& x) const
    2184              :                 {
    2185              :                         check_multi_index(ind);
    2186              :                         //ReferenceHexahedron::check_position(x);
    2187              : 
    2188              :                 //      loop dimensions
    2189        15840 :                         for(int d = 0; d < dim; ++d)
    2190              :                         {
    2191        11880 :                                 g[d] = m_vDPolynom[ind[d]].value(x[d]);
    2192              : 
    2193              :                         //      multiply by all functions not depending on x[d]
    2194        47520 :                                 for(int d2 = 0; d2 < dim; ++d2)
    2195              :                                 {
    2196              :                                 //      skip own value
    2197        35640 :                                         if(d2 == d) continue;
    2198              : 
    2199        47520 :                                         g[d] *= m_vPolynom[ind[d2]].value(x[d2]);
    2200              :                                 }
    2201              :                         }
    2202         3960 :                 }
    2203              : 
    2204              :         ///     return Multi index for index i
    2205            0 :                 inline const MathVector<dim,int>& multi_index(size_t i) const
    2206              :                 {
    2207              :                         check_index(i);
    2208        17706 :                         return m_vMultiIndex[i];
    2209              :                 }
    2210              : 
    2211              :         ///     return the index for a multi_index
    2212           99 :                 inline size_t index(const MathVector<dim,int>& ind) const
    2213              :                 {
    2214              :                         check_multi_index(ind);
    2215         2494 :                         for(size_t i=0; i<nsh; ++i)
    2216         2494 :                                 if(multi_index(i) == ind) return i;
    2217            0 :                         UG_THROW("Index not found in LagrangeLSFS");
    2218              :                 }
    2219              : 
    2220              :         ///     return the index for a multi_index
    2221            0 :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
    2222              :                 {
    2223              :                         check_multi_index(ind);
    2224              : 
    2225            0 :                         return ind[2] * (p+1)*(p+1) + ind[1] * (p+1) + ind[0];
    2226              :                 }
    2227              : 
    2228              :         ///     return the multi_index for an index
    2229            0 :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
    2230              :                 {
    2231              :                         check_index(i);
    2232              : 
    2233            0 :                         return MathVector<dim,int>( i%(p+1), i/(p+1)%(p+1), i/((p+1)*(p+1)));
    2234              :                 }
    2235              : 
    2236              :         ///     checks in debug mode that index is valid
    2237            0 :                 inline void check_index(size_t i) const
    2238              :                 {
    2239              :                         UG_ASSERT(i < nsh, "Wrong index.");
    2240            0 :                 }
    2241              : 
    2242              :         ///     checks in debug mode that multi-index is valid
    2243            0 :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
    2244              :                 {
    2245              :                         UG_ASSERT(ind[0] <= (int)p && ind[0] >= 0, "Wrong Multiindex.");
    2246              :                         UG_ASSERT(ind[1] <= (int)p && ind[1] >= 0, "Wrong Multiindex.");
    2247              :                         UG_ASSERT(ind[2] <= (int)p && ind[2] >= 0, "Wrong Multiindex.");
    2248            0 :                 }
    2249              : 
    2250              :         private:
    2251              :                 Polynomial1D m_vPolynom[p+1];
    2252              :                 Polynomial1D m_vDPolynom[p+1];
    2253              : 
    2254              :                 MathVector<dim,int> m_vMultiIndex[nsh];
    2255              : };
    2256              : 
    2257              : template <>
    2258              : class FlexLagrangeLSFS<ReferenceHexahedron>
    2259              :         : public LagrangeLDS<ReferenceHexahedron>,
    2260              :           public BaseLSFS<FlexLagrangeLSFS<ReferenceHexahedron>, 3>
    2261              : {
    2262              :         public:
    2263              :         ///     Dimension, where shape functions are defined
    2264              :                 static const int dim = ReferenceHexahedron::dim;
    2265              : 
    2266              :         public:
    2267              :         ///     default Constructor
    2268            0 :                 FlexLagrangeLSFS() {set_order(1);}
    2269              : 
    2270              :         ///     Constructor
    2271            0 :                 FlexLagrangeLSFS(size_t order) {set_order(order);}
    2272              : 
    2273              :         ///     sets the order
    2274              :                 void set_order(size_t order);
    2275              : 
    2276              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
    2277              :                 inline bool continuous() const {return true;}
    2278              : 
    2279              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
    2280            0 :                 inline size_t num_sh() const {return nsh;}
    2281              : 
    2282              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
    2283              :                 inline bool position(size_t i, MathVector<dim>& pos) const
    2284              :                 {
    2285              :                 //      get Multi Index
    2286              :                         MathVector<dim,int> ind = multi_index(i);
    2287              : 
    2288              :                 //      set position
    2289            0 :                         for(int d = 0; d < dim; ++d)
    2290            0 :                                 pos[d] = EquidistantLagrange1D::position(ind[d], p);
    2291              : 
    2292              :                         return true;
    2293              :                 }
    2294              : 
    2295              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
    2296              :                 inline number shape(const size_t i, const MathVector<dim>& x) const
    2297              :                 {
    2298              :                 //      forward
    2299            0 :                         return shape(multi_index(i), x);
    2300              :                 }
    2301              : 
    2302              :         ///     shape value for a Multi Index
    2303            0 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
    2304              :                 {
    2305              :                         check_multi_index(ind);
    2306              :                         //ReferenceHexahedron::check_position(x);
    2307              : 
    2308            0 :                         return    m_vPolynom[ ind[0] ].value(x[0])
    2309            0 :                                         * m_vPolynom[ ind[1] ].value(x[1])
    2310            0 :                                         * m_vPolynom[ ind[2] ].value(x[2]);
    2311              :                 }
    2312              : 
    2313              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
    2314            0 :                 inline void grad(grad_type& g, const size_t i, const MathVector<dim>& x) const
    2315              :                 {
    2316            0 :                         grad(g, multi_index(i), x);
    2317            0 :                 }
    2318              : 
    2319              :         ///     evaluates the gradient
    2320            0 :                 inline void grad(grad_type& g, const MathVector<dim,int> ind,
    2321              :                                                         const MathVector<dim>& x) const
    2322              :                 {
    2323              :                         check_multi_index(ind);
    2324              :                         //ReferenceHexahedron::check_position(x);
    2325              : 
    2326              :                 //      loop dimensions
    2327            0 :                         for(int d = 0; d < dim; ++d)
    2328              :                         {
    2329            0 :                                 g[d] = m_vDPolynom[ind[d]].value(x[d]);
    2330              : 
    2331              :                         //      multiply by all functions not depending on x[d]
    2332            0 :                                 for(int d2 = 0; d2 < dim; ++d2)
    2333              :                                 {
    2334              :                                 //      skip own value
    2335            0 :                                         if(d2 == d) continue;
    2336              : 
    2337            0 :                                         g[d] *= m_vPolynom[ind[d2]].value(x[d2]);
    2338              :                                 }
    2339              :                         }
    2340            0 :                 }
    2341              : 
    2342              :         ///     return Multi index for index i
    2343              :                 inline const MathVector<dim,int>& multi_index(size_t i) const
    2344              :                 {
    2345              :                         check_index(i);
    2346              :                         return m_vMultiIndex[i];
    2347              :                 }
    2348              : 
    2349              :         ///     return the index for a multi_index
    2350            0 :                 inline size_t index(const MathVector<dim,int>& ind) const
    2351              :                 {
    2352              :                         check_multi_index(ind);
    2353            0 :                         for(size_t i=0; i<nsh; ++i)
    2354            0 :                                 if(multi_index(i) == ind) return i;
    2355            0 :                         UG_THROW("Index not found in LagrangeLSFS");
    2356              :                 }
    2357              : 
    2358              :         ///     return the index for a multi_index
    2359              :                 inline size_t mapped_index(const MathVector<dim,int>& ind) const
    2360              :                 {
    2361              :                         check_multi_index(ind);
    2362              : 
    2363              :                         return ind[2] * (p+1)*(p+1) + ind[1] * (p+1) + ind[0];
    2364              :                 }
    2365              : 
    2366              :         ///     return the multi_index for an index
    2367              :                 inline MathVector<dim,int> mapped_multi_index(size_t i) const
    2368              :                 {
    2369              :                         check_index(i);
    2370              : 
    2371              :                         return MathVector<dim,int>( i%(p+1), i/(p+1)%(p+1), i/((p+1)*(p+1)));
    2372              :                 }
    2373              : 
    2374              :         ///     checks in debug mode that index is valid
    2375              :                 inline void check_index(size_t i) const
    2376              :                 {
    2377              :                         UG_ASSERT(i < nsh, "Wrong index.");
    2378              :                 }
    2379              : 
    2380              :         ///     checks in debug mode that multi-index is valid
    2381              :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
    2382              :                 {
    2383              :                         UG_ASSERT(ind[0] <= (int)p && ind[0] >= 0, "Wrong Multiindex.");
    2384              :                         UG_ASSERT(ind[1] <= (int)p && ind[1] >= 0, "Wrong Multiindex.");
    2385              :                         UG_ASSERT(ind[2] <= (int)p && ind[2] >= 0, "Wrong Multiindex.");
    2386              :                 }
    2387              : 
    2388              :         private:
    2389              :         ///     order
    2390              :                 size_t p;
    2391              : 
    2392              :         /// Number of shape functions
    2393              :                 size_t nsh;
    2394              : 
    2395              :                 std::vector<Polynomial1D> m_vPolynom;     ///< Shape Polynomials
    2396              :                 std::vector<Polynomial1D> m_vDPolynom;    ///< Derivative of Shape Polynomial
    2397              : 
    2398              :                 std::vector<MathVector<dim,int> > m_vMultiIndex;
    2399              : };
    2400              : 
    2401              : ///////////////////////////////////////////////////////////////////////////////
    2402              : // Octahedron
    2403              : ///////////////////////////////////////////////////////////////////////////////
    2404              : 
    2405              : //      NOTE:   Currently only 1st order is implemented. There is no shape function
    2406              : //                      set for octahedrons, that is continuous and allows a continuous
    2407              : //                      derivative in the inner of the pyramid. This is basically, since
    2408              : //                      one regards the octahedron as 4 tetrahedrons, glued together.
    2409              : template <int TOrder>
    2410              : class LagrangeLSFS<ReferenceOctahedron, TOrder>
    2411              :         : public LagrangeLDS<ReferenceOctahedron>,
    2412              :           public BaseLSFS<LagrangeLSFS<ReferenceOctahedron, TOrder>, 3>
    2413              : {
    2414              :         private:
    2415              :         ///     abbreviation for order
    2416              :                 static const size_t p = TOrder;
    2417              : 
    2418              :         ///     base class
    2419              :                 typedef BaseLSFS<LagrangeLSFS<ReferenceOctahedron, TOrder>, 3> base_type;
    2420              : 
    2421              :         public:
    2422              :         ///     Shape type
    2423              :                 typedef typename base_type::shape_type shape_type;
    2424              : 
    2425              :         ///     Gradient type
    2426              :                 typedef typename base_type::grad_type grad_type;
    2427              : 
    2428              :         public:
    2429              :         ///     Order of Shape functions
    2430              :                 static const size_t order = TOrder;
    2431              : 
    2432              :         ///     Dimension, where shape functions are defined
    2433              :                 static const int dim = 3;       //reference_element_type::dim; (compile error on OSX 10.5)
    2434              : 
    2435              :         /// Number of shape functions
    2436              :                 static const size_t nsh = 6;
    2437              : 
    2438              :         public:
    2439              :         ///     Constructor
    2440              :                 LagrangeLSFS();
    2441              : 
    2442              :         ///     \copydoc ug::LocalShapeFunctionSet::continuous()
    2443            0 :                 inline bool continuous() const {return true;}
    2444              : 
    2445              :         ///     \copydoc ug::LocalShapeFunctionSet::num_sh()
    2446            0 :                 inline size_t num_sh() const {return nsh;}
    2447              : 
    2448              :         ///     \copydoc ug::LocalShapeFunctionSet::position()
    2449            0 :                 inline bool position(size_t i, MathVector<dim>& pos) const
    2450              :                 {
    2451              :                 //      get Multi Index
    2452              :                         MathVector<dim,int> ind = multi_index(i);
    2453              : 
    2454              :                 //      set position
    2455            0 :                         for(int d = 0; d < dim; ++d)
    2456            0 :                                 pos[d] = EquidistantLagrange1D::position(ind[d], p);
    2457              : 
    2458            0 :                         return true;
    2459              :                 }
    2460              : 
    2461              :         ///     \copydoc ug::LocalShapeFunctionSet::shape()
    2462            0 :                 inline number shape(const size_t i, const MathVector<dim>& x) const
    2463              :                 {
    2464              :                 //      only first order
    2465              :                         if(p != 1) UG_THROW("Only 1. order Lagrange Octahedron implemented.");
    2466              : 
    2467              :                 //      shape analogously to pyramidal case introducing additional distinction of cases
    2468              :                 //      z >= 0 and z < 0
    2469            0 :                         const number z_sgn      = (x[2] < 0) ? -1.0 : 1.0;
    2470              : 
    2471            0 :                         switch(i)
    2472              :                         {
    2473              :                           case 0 :
    2474            0 :                                 if (x[2] < 0)
    2475            0 :                                   return(-1.0*x[2]);
    2476              :                                 else
    2477              :                                   return(0.0);
    2478              :                           case 1 :
    2479            0 :                                 if (x[0] > x[1])
    2480            0 :                                   return((1.0-x[0])*(1.0-x[1]) + z_sgn*x[2]*(x[1]-1.0));
    2481              :                                 else
    2482            0 :                                   return((1.0-x[0])*(1.0-x[1]) + z_sgn*x[2]*(x[0]-1.0));
    2483              :                           case 2 :
    2484            0 :                                 if (x[0] > x[1])
    2485            0 :                                   return(x[0]*(1.0-x[1])       - z_sgn*x[2]*x[1]);
    2486              :                                 else
    2487            0 :                                   return(x[0]*(1.0-x[1])       - z_sgn*x[2]*x[0]);
    2488              :                           case 3 :
    2489            0 :                                 if (x[0] > x[1])
    2490            0 :                                   return(x[0]*x[1]             + z_sgn*x[2]*x[1]);
    2491              :                                 else
    2492            0 :                                   return(x[0]*x[1]             + z_sgn*x[2]*x[0]);
    2493              :                           case 4 :
    2494            0 :                                 if (x[0] > x[1])
    2495            0 :                                   return((1.0-x[0])*x[1]       - z_sgn*x[2]*x[1]);
    2496              :                                 else
    2497            0 :                                   return((1.0-x[0])*x[1]       - z_sgn*x[2]*x[0]);
    2498              :                           case 5 :
    2499            0 :                                 if (x[2] < 0)
    2500            0 :                                   return(0.0);
    2501              :                                 else
    2502              :                                   return(x[2]);
    2503            0 :                           default: UG_THROW("Wrong index "<< i<<" in Octahedron.");
    2504              :                         }
    2505              :                 }
    2506              : 
    2507              :         ///     shape value for a Multi Index
    2508            0 :                 inline number shape(const MathVector<dim,int>& ind, const MathVector<dim>& x) const
    2509              :                 {
    2510              :                         check_multi_index(ind);
    2511              : 
    2512              :                 //      forward
    2513            0 :                         return shape(index(ind), x);
    2514              :                 }
    2515              : 
    2516              :         ///     \copydoc ug::LocalShapeFunctionSet::grad()
    2517            0 :                 inline void grad(grad_type& g, const size_t i, const MathVector<dim>& x) const
    2518              :                 {
    2519              :                 //      only first order
    2520              :                         if(p != 1) UG_THROW("Only 1. order Lagrange Octahedron implemented.");
    2521              : 
    2522              :                         //      shape analogously to pyramidal case introducing additional distinction of cases
    2523              :                         //      z >= 0 and z < 0
    2524            0 :                                 const number z_sgn      = (x[2] < 0) ? -1.0 : 1.0;
    2525              : 
    2526            0 :                                 switch(i)
    2527              :                                 {
    2528              :                                   case 0:
    2529            0 :                                         if (x[2] < 0.0)
    2530              :                                         {
    2531            0 :                                                 g[0] = 0.0;
    2532            0 :                                                 g[1] = 0.0;
    2533            0 :                                                 g[2] = -1.0;
    2534            0 :                                                 break;
    2535              :                                         }
    2536              :                                         else
    2537              :                                         {
    2538            0 :                                                 g[0] = 0.0;
    2539            0 :                                                 g[1] = 0.0;
    2540            0 :                                                 g[2] = 0.0;
    2541            0 :                                                 break;
    2542              :                                         }
    2543              :                                   case 1:
    2544            0 :                                         if (x[0] > x[1])
    2545              :                                           {
    2546            0 :                                                 g[0] = -(1.0-x[1]);
    2547            0 :                                                 g[1] = -(1.0-x[0]) + z_sgn*x[2];
    2548            0 :                                                 g[2] = -z_sgn*(1.0-x[1]);
    2549            0 :                                                 break;
    2550              :                                           }
    2551              :                                         else
    2552              :                                           {
    2553            0 :                                                 g[0] = -(1.0-x[1]) + z_sgn*x[2];
    2554            0 :                                                 g[1] = -(1.0-x[0]);
    2555            0 :                                                 g[2] = -z_sgn*(1.0-x[0]);
    2556            0 :                                                 break;
    2557              :                                           }
    2558              :                                   case 2:
    2559            0 :                                         if (x[0] > x[1])
    2560              :                                           {
    2561            0 :                                                 g[0] = (1.0-x[1]);
    2562            0 :                                                 g[1] = -x[0] - z_sgn*x[2];
    2563            0 :                                                 g[2] = -z_sgn*x[1];
    2564            0 :                                                 break;
    2565              :                                           }
    2566              :                                         else
    2567              :                                           {
    2568            0 :                                                 g[0] = (1.0-x[1]) - z_sgn*x[2];
    2569            0 :                                                 g[1] = -x[0];
    2570            0 :                                                 g[2] = -z_sgn*x[0];
    2571            0 :                                                 break;
    2572              :                                           }
    2573              :                                   case 3:
    2574            0 :                                         if (x[0] > x[1])
    2575              :                                           {
    2576            0 :                                                 g[0] = x[1];
    2577            0 :                                                 g[1] = x[0] + z_sgn*x[2];
    2578            0 :                                                 g[2] = z_sgn*x[1];
    2579            0 :                                                 break;
    2580              :                                           }
    2581              :                                         else
    2582              :                                           {
    2583            0 :                                                 g[0] = x[1] + z_sgn*x[2];
    2584            0 :                                                 g[1] = x[0];
    2585            0 :                                                 g[2] = z_sgn*x[0];
    2586            0 :                                                 break;
    2587              :                                           }
    2588              :                                   case 4:
    2589            0 :                                         if (x[0] > x[1])
    2590              :                                           {
    2591            0 :                                                 g[0] = -x[1];
    2592            0 :                                                 g[1] = 1.0-x[0] - z_sgn*x[2];
    2593            0 :                                                 g[2] = -z_sgn*x[1];
    2594            0 :                                                 break;
    2595              :                                           }
    2596              :                                         else
    2597              :                                           {
    2598            0 :                                                 g[0] = -x[1] - z_sgn*x[2];
    2599            0 :                                                 g[1] = 1.0-x[0];
    2600            0 :                                                 g[2] = -z_sgn*x[0];
    2601            0 :                                                 break;
    2602              :                                           }
    2603              :                               case 5:
    2604            0 :                                 if (x[2] < 0.0)
    2605              :                                 {
    2606            0 :                                         g[0] = 0.0;
    2607            0 :                                         g[1] = 0.0;
    2608            0 :                                         g[2] = 0.0;
    2609            0 :                                         break;
    2610              :                                 }
    2611              :                                 else
    2612              :                                 {
    2613            0 :                                         g[0] = 0.0;
    2614            0 :                                         g[1] = 0.0;
    2615            0 :                                         g[2] = 1.0;
    2616            0 :                                         break;
    2617              :                                 }
    2618            0 :                               default: UG_THROW("Wrong index "<< i<<" in Octahedron.");
    2619              :                                 }
    2620            0 :                 }
    2621              : 
    2622              :         ///     evaluates the gradient
    2623            0 :                 inline void grad(grad_type& g, const MathVector<dim,int> ind,
    2624              :                                                                    const MathVector<dim>& x) const
    2625              :                 {
    2626            0 :                         grad(g, index(ind), x);
    2627            0 :                 }
    2628              : 
    2629              :         ///     return Multi index for index i
    2630            0 :                 inline const MathVector<dim,int>& multi_index(size_t i) const
    2631              :                 {
    2632              :                         check_index(i);
    2633            0 :                         return m_vMultiIndex[i];
    2634              :                 }
    2635              : 
    2636              :         ///     return the index for a multi_index
    2637            0 :                 inline size_t index(const MathVector<dim,int>& ind) const
    2638              :                 {
    2639              :                         check_multi_index(ind);
    2640            0 :                         for(size_t i=0; i<nsh; ++i)
    2641            0 :                                 if(multi_index(i) == ind) return i;
    2642            0 :                         UG_THROW("Index not found in LagrangeLSFS");
    2643              :                 }
    2644              : 
    2645              :         ///     checks in debug mode that index is valid
    2646            0 :                 inline void check_index(size_t i) const
    2647              :                 {
    2648              :                         UG_ASSERT(i < nsh, "Wrong index.");
    2649            0 :                 }
    2650              : 
    2651              :         ///     checks in debug mode that multi-index is valid
    2652            0 :                 inline void check_multi_index(const MathVector<dim,int>& ind) const
    2653              :                 {
    2654              :                         UG_ASSERT(ind[0] <= (int)p-ind[2] && ind[0] >= 0, "Wrong Multiindex.");
    2655              :                         UG_ASSERT(ind[1] <= (int)p-ind[2] && ind[1] >= 0, "Wrong Multiindex.");
    2656              :                         UG_ASSERT(ind[2] <= (int)p && ind[2] >= 0, "Wrong Multiindex.");
    2657            0 :                 }
    2658              : 
    2659              :         private:
    2660              : 
    2661              :                 MathVector<dim,int> m_vMultiIndex[nsh];
    2662              : };
    2663              : 
    2664              : 
    2665              : } //namespace ug
    2666              : 
    2667              : #endif /* __H__UG__LIB_DISC__LOCAL_SHAPE_FUNCTION_SET__LAGRANGE__LAGRANGE__ */
    2668              : 
        

Generated by: LCOV version 2.0-1