]> https://gitweb.dealii.org/ - dealii-svn.git/commitdiff
Nedelec elements in prerelease version. Requires documentation and style changes...
authorbuerg <buerg@0785d39b-7218-0410-832d-ea1e28bc413d>
Sun, 12 Sep 2010 09:03:07 +0000 (09:03 +0000)
committerbuerg <buerg@0785d39b-7218-0410-832d-ea1e28bc413d>
Sun, 12 Sep 2010 09:03:07 +0000 (09:03 +0000)
git-svn-id: https://svn.dealii.org/trunk@21932 0785d39b-7218-0410-832d-ea1e28bc413d

deal.II/base/include/base/polynomial.h
deal.II/base/include/base/polynomials_nedelec.h [new file with mode: 0644]
deal.II/base/source/polynomial.cc
deal.II/base/source/polynomials_nedelec.cc [new file with mode: 0644]
deal.II/deal.II/include/fe/fe_nedelec.h
deal.II/deal.II/source/fe/fe_nedelec.cc
deal.II/deal.II/source/fe/fe_poly_tensor.cc

index 81f8b79c47fd44482bf2b1f3d3b76f9881e44a9e..c9c4514c4523e19fda260669f22cb9eae2c030fd 100644 (file)
@@ -2,7 +2,7 @@
 //    $Id$
 //    Version: $Name$
 //
-//    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 by the deal.II authors
+//    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 by the deal.II authors
 //
 //    This file is subject to QPL and may not be  distributed
 //    without copyright and license information. Please refer
@@ -18,7 +18,6 @@
 #include <base/config.h>
 #include <base/exceptions.h>
 #include <base/subscriptor.h>
-#include <base/std_cxx1x/shared_ptr.h>
 
 #include <vector>
 
@@ -44,7 +43,7 @@ namespace Polynomials
  * happens through the Horner scheme which provides both numerical
  * stability and a minimal number of numerical operations.
  *
- * @author Ralf Hartmann, Guido Kanschat, 2000, 2006, 2009
+ * @author Ralf Hartmann, Guido Kanschat, 2000, 2006
  */
   template <typename number>
   class Polynomial : public Subscriptor
@@ -69,18 +68,12 @@ namespace Polynomials
                                         */
       Polynomial (const std::vector<number> &coefficients);
 
-                                      /**
-                                       * Constructor creating a zero
-                                       * polynomial of degree @p n.
-                                       */
-      Polynomial (const unsigned int n);
-
                                       /**
                                        * Default constructor creating
                                        * an illegal object.
                                        */
       Polynomial ();
-
+      
                                        /**
                                         * Return the value of this
                                         * polynomial at the given point.
@@ -90,7 +83,7 @@ namespace Polynomials
                                         * of the evaluation.
                                         */
       number value (const number x) const;
-
+    
                                        /**
                                         * Return the values and the
                                         * derivatives of the
@@ -194,12 +187,12 @@ namespace Polynomials
                                        * Add a second polynomial.
                                        */
       Polynomial<number>& operator += (const Polynomial<number>& p);
-
+      
                                       /**
                                        * Subtract a second polynomial.
                                        */
       Polynomial<number>& operator -= (const Polynomial<number>& p);
-
+      
                                        /**
                                         * Print coefficients.
                                         */
@@ -227,7 +220,7 @@ namespace Polynomials
                                         */
       static void multiply (std::vector<number>& coefficients,
                             const number factor);
-
+    
                                        /**
                                         * Coefficients of the polynomial
                                         * $\sum_i a_i x^i$. This vector
@@ -279,7 +272,7 @@ namespace Polynomials
       static
       std::vector<Polynomial<number> >
       generate_complete_basis (const unsigned int degree);
-
+    
     private:
                                       /**
                                        * Needed by constructor.
@@ -287,7 +280,7 @@ namespace Polynomials
       static std::vector<number> make_vector(unsigned int n,
                                             const double coefficient);
   };
-
+  
 
 /**
  * Lagrange polynomials with equidistant interpolation points in
@@ -341,7 +334,7 @@ namespace Polynomials
       static
       std::vector<Polynomial<double> >
       generate_complete_basis (const unsigned int degree);
-
+    
     private:
 
                                        /**
@@ -352,11 +345,10 @@ namespace Polynomials
                                         * called in the
                                         * constructor.
                                         */
-      static
-      void
+      static 
+      std::vector<double> 
       compute_coefficients (const unsigned int n,
-                            const unsigned int support_point,
-                           std::vector<double>& a);
+                            const unsigned int support_point);
   };
 
 /**
@@ -381,9 +373,9 @@ namespace Polynomials
       std::vector<Polynomial<double> >
       generate_complete_basis (const std::vector<Point<1> >& points);
   };
-
-
-
+  
+  
+  
 /**
  * Legendre polynomials of arbitrary degree on <tt>[0,1]</tt>.
  *
@@ -420,33 +412,30 @@ namespace Polynomials
       static
       std::vector<Polynomial<double> >
       generate_complete_basis (const unsigned int degree);
-
+    
     private:
                                        /**
                                         * Coefficients for the interval $[0,1]$.
                                         */
-      static std::vector<std_cxx1x::shared_ptr<const std::vector<double> > > shifted_coefficients;
-
+      static std::vector<const std::vector<double> *> shifted_coefficients;
+    
                                        /**
                                         * Vector with already computed
-                                        * coefficients. For each degree of the
-                                        * polynomial, we keep one pointer to
-                                        * the list of coefficients; we do so
-                                        * rather than keeping a vector of
+                                        * coefficients. For each degree
+                                        * of the polynomial, we keep one
+                                        * pointer to the list of
+                                        * coefficients; we do so rather
+                                        * than keeping a vector of
                                         * vectors in order to simplify
-                                        * programming multithread-safe. In
-                                        * order to avoid memory leak, we use a
-                                        * shared_ptr in order to correctly
-                                        * free the memory of the vectors when
-                                        * the global destructor is called.
+                                        * programming multithread-safe.
                                         */
-      static std::vector<std_cxx1x::shared_ptr<const std::vector<double> > > recursive_coefficients;
-
+      static std::vector<const std::vector<double> *> recursive_coefficients;
+    
                                        /**
                                         * Compute coefficients recursively.
                                         */
       static void compute_coefficients (const unsigned int p);
-
+    
                                        /**
                                         * Get coefficients for
                                         * constructor.  This way, it can
@@ -458,28 +447,57 @@ namespace Polynomials
       get_coefficients (const unsigned int k);
   };
 
-
+/**
+ * Lobatto polynomials of arbitrary degree on <tt>[0,1]</tt>.
+ *
+ * These polynomials are the integrated Legendre polynomials on [0,1]. The first two polynomials are the standard linear shape functions given by $l_0(x) = 1-x$ and $l_1(x) = x$. For $i\geq2$ we use the definition $l_i(x) = \frac{1}{\Vert L_{i-1}\Vert_2}\int_0^x L_{i-1}(t)\,dt, where L_i deontes the i-th Legendre polynomial on [0,1]. The Lobatto polynomials l_0,\ldots,l_k form a complete basis of the polynomials space of degree k.
+ *
+ * Calling the constructor with a given index <tt>k</tt> will generate the polynomial with index <tt>k</tt>. But only for $k\geq1$ the index equals the degree of the polynomial. For <tt>k==0</tt> also a polynomial of degree 1 is generated.
+ *
+ * These polynomials are used for the construction of the shape functions of Nédélec elements of arbitrary order.
+ *
+ * @author Markus Bürg, 2009
+ */
+class Lobatto : public Polynomial<double> {
+   public:
+   /**
+       * Constructor for polynomial of degree <tt>p</tt>. There is an exception for <tt>p==0</tt>, see the general documentation.
+       */
+      Lobatto (const unsigned int p = 0);
+
+   /**
+       * Return the polynomials with index <tt>0</tt> up to <tt>degree</tt>. There is an exception for <tt>p==0</tt>, see the general
+    * documentation.
+       */
+      static std::vector<Polynomial<double> > generate_complete_basis (const unsigned int p);
+
+   private:
+   /**
+    * Compute coefficients recursively.
+    */
+      std::vector<double> compute_coefficients (const unsigned int p);
+};
 
 /**
  * Hierarchical polynomials of arbitrary degree on <tt>[0,1]</tt>.
  *
- * When Constructing a Hierarchical polynomial of degree <tt>p</tt>,
+ * When Constructing a Hierarchical polynomial of degree <tt>p</tt>, 
  * the coefficients will be computed by a recursion formula.  The
  * coefficients are stored in a static data vector to be available
  * when needed next time.
  *
- * These hierarchical polynomials are based on those of Demkowicz, Oden,
+ * These hierarchical polynomials are based on those of Demkowicz, Oden, 
  * Rachowicz, and Hardy (CMAME 77 (1989) 79-112, Sec. 4). The first two
- * polynomials are the standard linear shape functions given by
+ * polynomials are the standard linear shape functions given by 
  * $\phi_{0}(x) = 1 - x$ and $\phi_{1}(x) = x$. For $l \geq 2$
  * we use the definitions $\phi_{l}(x) = (2x-1)^l - 1, l = 2,4,6,...$
- * and $\phi_{l}(x) = (2x-1)^l - (2x-1), l = 3,5,7,...$. These satisfy the
- * recursion relations $\phi_{l}(x) = (2x-1)\phi_{l-1}, l=3,5,7,...$ and
- * $\phi_{l}(x) = (2x-1)\phi_{l-1} + \phi_{2}, l=4,6,8,...$.
+ * and $\phi_{l}(x) = (2x-1)^l - (2x-1), l = 3,5,7,...$. These satisfy the 
+ * recursion relations $\phi_{l}(x) = (2x-1)\phi_{l-1}, l=3,5,7,...$ and 
+ * $\phi_{l}(x) = (2x-1)\phi_{l-1} + \phi_{2}, l=4,6,8,...$. 
  *
- * The degrees of freedom are the values at the vertices and the
+ * The degrees of freedom are the values at the vertices and the 
  * derivatives at the midpoint. Currently, we do not scale the
- * polynomials in any way, although better conditioning of the
+ * polynomials in any way, although better conditioning of the 
  * element stiffness matrix could possibly be achieved with scaling.
  *
  * Calling the constructor with a given index <tt>p</tt> will generate the
@@ -533,7 +551,7 @@ namespace Polynomials
       static
       std::vector<Polynomial<double> >
       generate_complete_basis (const unsigned int degree);
-
+    
     private:
                                     /**
                                      * Compute coefficients recursively.
@@ -549,22 +567,22 @@ namespace Polynomials
                                      */
      static const std::vector<double> &
      get_coefficients (const unsigned int p);
-
      static std::vector<const std::vector<double> *> recursive_coefficients;
-   };
+   };  
 }
 
 /** @} */
 
 /* -------------------------- inline functions --------------------- */
 
-namespace Polynomials
+namespace Polynomials 
 {
   template <typename number>
   inline
-  Polynomial<number>::Polynomial ()
+  Polynomial<number>::Polynomial () 
   {}
-
+  
   template <typename number>
   inline
   unsigned int
diff --git a/deal.II/base/include/base/polynomials_nedelec.h b/deal.II/base/include/base/polynomials_nedelec.h
new file mode 100644 (file)
index 0000000..90f419f
--- /dev/null
@@ -0,0 +1,150 @@
+#ifndef __deal2__polynomials_nedelec_h
+#define __deal2__polynomials_nedelec_h
+
+
+#include <base/config.h>
+#include <base/exceptions.h>
+#include <base/tensor.h>
+#include <base/point.h>
+#include <base/polynomial.h>
+#include <base/polynomial_space.h>
+#include <base/tensor_product_polynomials.h>
+#include <base/table.h>
+
+#include <vector>
+
+DEAL_II_NAMESPACE_OPEN
+/**
+ * @addtogroup Polynomials
+ * @{
+ */
+
+/**
+ * This class implements the <i>H<sup>curl</sup></i>-conforming,
+ * vector-valued Nédélec polynomials as proposed in the book of
+ * P. Solin, K. Segeth and I. Dolezel.
+ *
+ * The Nédélec polynomials are constructed such that the curl
+ * is in the tensor product polynomial space <i>Q<sub>k</sub></i>.
+ * Therefore, the polynomial order of each component must be one
+ * order higher in the corresponding two directions,
+ * yielding the polynomial spaces <i>(Q<sub>k,k+1</sub>,
+ * Q<sub>k+1,k</sub>)</i> and <i>(Q<sub>k,k+1,k+1</sub>,
+ * Q<sub>k+1,k,k+1</sub>, Q<sub>k+1,k+1,k</sub>)</i> in 2D and 3D, resp.
+ *
+ * @author Markus Bürg, 2009
+ */
+template <int dim>
+class PolynomialsNedelec
+{
+  public:
+                                    /**
+                                     * Constructor. Creates all basis
+                                     * functions for Nédélec polynomials
+                                     * of given degree.
+                                     *
+                                     * @arg k: the degree of the
+                                     * Nédélec space, which is the degree
+                                     * of the largest tensor product
+                                     * polynomial space
+                                     * <i>Q<sub>k</sub></i> contained.
+                                     */
+    PolynomialsNedelec (const unsigned int k);
+    
+                                    /**
+                                     * Computes the value and the
+                                     * first and second derivatives
+                                     * of each Nédélec
+                                     * polynomial at @p unit_point.
+                                     *
+                                     * The size of the vectors must
+                                     * either be zero or equal
+                                     * <tt>n()</tt>.  In the
+                                     * first case, the function will
+                                     * not compute these values.
+                                     *
+                                     * If you need values or
+                                     * derivatives of all tensor
+                                     * product polynomials then use
+                                     * this function, rather than
+                                     * using any of the
+                                     * <tt>compute_value</tt>,
+                                     * <tt>compute_grad</tt> or
+                                     * <tt>compute_grad_grad</tt>
+                                     * functions, see below, in a
+                                     * loop over all tensor product
+                                     * polynomials.
+                                     */
+    void compute (const Point<dim> &unit_point, std::vector<Tensor<1, dim> > &values, std::vector<Tensor<2, dim> > &grads, std::vector<Tensor<3, dim> > &grad_grads) const;
+
+                                    /**
+                                     * Returns the number of Nédélec
+                                       * polynomials.
+                                     */
+    unsigned int n () const;
+    
+                                    /**
+                                     * Returns the degree of the Nédélec
+                                     * space, which is one less than
+                                     * the highest polynomial degree.
+                                     */
+    unsigned int degree () const;
+    
+                                    /**
+                                     * Return the number of
+                                     * polynomials in the space
+                                     * <TT>N(degree)</tt> without
+                                     * requiring to build an object
+                                     * of PolynomialsNedelec. This is
+                                     * required by the FiniteElement
+                                     * classes.
+                                     */
+    static unsigned int compute_n_pols (unsigned int degree);
+    
+  private:
+                                    /**
+                                     * The degree of this object as
+                                     * given to the constructor.
+                                     */
+    const unsigned int my_degree;
+    
+                                    /**
+                                     * An object representing the
+                                     * polynomial space for a single
+                                     * component. We can re-use it by
+                                     * rotating the coordinates of
+                                     * the evaluation point.
+                                     */
+    const AnisotropicPolynomials<dim> polynomial_space;
+
+                                    /**
+                                     * Number of Nédélec polynomials.
+                                     */
+    const unsigned int n_pols;
+
+                                    /**
+                                     * A static member function that
+                                     * creates the polynomial space
+                                     * we use to initialize the
+                                     * #polynomial_space member
+                                     * variable.
+                                     */
+    static std::vector<std::vector< Polynomials::Polynomial< double > > > create_polynomials (const unsigned int k);
+};
+
+/** @} */
+
+template <int dim>
+inline unsigned int PolynomialsNedelec<dim>::n () const
+{
+  return n_pols;
+}
+
+template <int dim>
+inline unsigned int PolynomialsNedelec<dim>::degree () const
+{
+  return my_degree;
+}
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
index b8663860e6f5106e68b8779a55cab460f3c8ba29..e82e048956444dc67c0c1e737e739c2772d426ad 100644 (file)
@@ -1,8 +1,8 @@
 //---------------------------------------------------------------------------
-//      $Id$
+//      $Id$   
 //    Version: $Name$
 //
-//    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010 by the deal.II authors
+//    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 by the deal.II authors
 //
 //    This file is subject to QPL and may not be  distributed
 //    without copyright and license information. Please refer
@@ -31,7 +31,7 @@ DEAL_II_NAMESPACE_OPEN
 // to be a problem since we only need it on very rare occasions. if
 // someone finds this is a bottleneck, feel free to replace it by a
 // more fine-grained solution
-namespace
+namespace 
 {
   Threads::ThreadMutex coefficients_lock;
 }
@@ -52,14 +52,6 @@ namespace Polynomials
 
 
 
-  template <typename number>
-  Polynomial<number>::Polynomial (const unsigned int n)
-                  :
-                  coefficients(n+1, 0.)
-  {}
-
-
-
   template <typename number>
   void
   Polynomial<number>::value (const number         x,
@@ -68,8 +60,8 @@ namespace Polynomials
     Assert (coefficients.size() > 0, ExcEmptyObject());
     Assert (values.size() > 0, ExcZero());
     const unsigned int values_size=values.size();
-
-
+  
+  
                                      // if we only need the value, then
                                      // call the other function since
                                      // that is significantly faster
@@ -124,7 +116,7 @@ namespace Polynomials
       {
         *c *= f;
         f *= factor;
-      }
+      }  
   }
 
 
@@ -160,7 +152,7 @@ namespace Polynomials
     return *this;
   }
 
-
+  
   template <typename number>
   Polynomial<number>&
   Polynomial<number>::operator *= (const Polynomial<number>& p)
@@ -169,16 +161,16 @@ namespace Polynomials
     unsigned int new_degree = this->degree() + p.degree();
 
     std::vector<number> new_coefficients(new_degree+1, 0.);
-
+    
     for (unsigned int i=0; i<p.coefficients.size(); ++i)
       for (unsigned int j=0; j<this->coefficients.size(); ++j)
       new_coefficients[i+j] += this->coefficients[j]*p.coefficients[i];
     this->coefficients = new_coefficients;
-
+    
     return *this;
   }
 
-
+  
   template <typename number>
   Polynomial<number>&
   Polynomial<number>::operator += (const Polynomial<number>& p)
@@ -194,7 +186,7 @@ namespace Polynomials
     return *this;
   }
 
-
+  
   template <typename number>
   Polynomial<number>&
   Polynomial<number>::operator -= (const Polynomial<number>& p)
@@ -210,13 +202,13 @@ namespace Polynomials
     return *this;
   }
 
-
+  
   template <typename number>
   template <typename number2>
   void
   Polynomial<number>::shift(std::vector<number>& coefficients,
                             const number2 offset)
-  {
+  {  
 #ifdef DEAL_II_LONG_DOUBLE_LOOP_BUG
     AssertThrow (false,
                  ExcMessage("Sorry, but the compiler you are using has a bug that disallows "
@@ -228,12 +220,12 @@ namespace Polynomials
                                      // args. note that this code is
                                      // actually unreachable
     coefficients[0] = offset;
-#else
+#else  
                                      // Copy coefficients to a vector of
                                      // accuracy given by the argument
     std::vector<number2> new_coefficients(coefficients.begin(),
                                           coefficients.end());
-
+  
                                      // Traverse all coefficients from
                                      // c_1. c_0 will be modified by
                                      // higher degrees, only.
@@ -250,7 +242,7 @@ namespace Polynomials
                                          // needed and computed
                                          // successively.
         number2 offset_power = offset;
-
+      
                                          // Compute (x+offset)^d
                                          // and modify all values c_k
                                          // with k<d.
@@ -291,7 +283,7 @@ namespace Polynomials
   }
 
 
-
+  
   template <typename number>
   Polynomial<number>
   Polynomial<number>::derivative () const
@@ -305,7 +297,7 @@ namespace Polynomials
 
     return Polynomial<number> (newcoefficients);
   }
-
+  
 
   template <typename number>
   Polynomial<number>
@@ -318,7 +310,7 @@ namespace Polynomials
 
     return Polynomial<number> (newcoefficients);
   }
-
+  
 
   template <typename number>
   void
@@ -343,15 +335,15 @@ namespace Polynomials
     result[n] = coefficient;
     return result;
   }
-
-
+  
+  
   template <typename number>
   Monomial<number>::Monomial (unsigned int n,
                              double coefficient)
                  : Polynomial<number>(make_vector(n, coefficient))
   {}
-
-
+  
+  
   template <typename number>
   std::vector<Polynomial<number> >
   Monomial<number>::generate_complete_basis (const unsigned int degree)
@@ -366,54 +358,24 @@ namespace Polynomials
 
   LagrangeEquidistant::LagrangeEquidistant (const unsigned int n,
                                             const unsigned int support_point)
-  {
-    if (n <= 10)
-      {
-       this->coefficients.resize(n+1);
-       compute_coefficients(n, support_point, this->coefficients);
-      }
-    else
-      {
-                                        // We have precomputed tables
-                                        // up to degree 10. For
-                                        // higher order, we have to
-                                        // compute by hand.
+                 :
+                  Polynomial<double>(compute_coefficients(n,support_point))
+  {}
 
-                                        // Start with the constant one
-       this->coefficients.resize(1);
-       this->coefficients[0] = 1.;
 
-                                        // Then compute the Lagrange
-                                        // polynomial as the product
-                                        // of linear factors
-       std::vector<double> two (2, 1.);
 
-       for (unsigned int k=0;k<=n;++k)
-         {
-           if (k != support_point)
-             {
-               two[0] = -1.*k/n;
-               Polynomial<double> factor(two);
-               factor.scale(1.*n/(support_point - k));
-               (*this) *= factor;
-             }
-         }
-      }
-  }
-
-
-  void
+  std::vector<double> 
   LagrangeEquidistant::compute_coefficients (const unsigned int n,
-                                             const unsigned int support_point,
-                                            std::vector<double>& a)
+                                             const unsigned int support_point)
   {
+    std::vector<double> a (n+1);
     Assert(support_point<n+1, ExcIndexRange(support_point, 0, n+1));
 
     unsigned int n_functions=n+1;
     Assert(support_point<n_functions,
            ExcIndexRange(support_point, 0, n_functions));
     double const *x=0;
-
+  
     switch (n)
       {
         case 1:
@@ -424,7 +386,7 @@ namespace Polynomials
                   0.0, 1.0
             };
           x=&x1[0];
-          break;
+          break;       
         }
         case 2:
         {
@@ -460,7 +422,7 @@ namespace Polynomials
                   0.0, -1.0, 22.0/3.0, -16.0, 32.0/3.0
             };
           x=&x4[0];
-          break;
+          break;       
         }
         case 5:
         {
@@ -613,12 +575,14 @@ namespace Polynomials
           break;
         }
         default:
-             Assert(false, ExcInternalError())
+              Assert(false, ExcNotImplemented());
       }
 
     Assert(x!=0, ExcInternalError());
     for (unsigned int i=0; i<n_functions; ++i)
       a[i]=x[support_point*n_functions+i];
+  
+    return a;
   }
 
 
@@ -644,7 +608,7 @@ namespace Polynomials
 
 //----------------------------------------------------------------------//
 
-
+  
   std::vector<Polynomial<double> >
   Lagrange::generate_complete_basis (const std::vector<Point<1> >& points)
   {
@@ -657,7 +621,7 @@ namespace Polynomials
     std::vector<double> linear(2, 1.);
                                     // We start with a constant polynomial
     std::vector<double> one(1, 1.);
-
+    
     for (unsigned int i=0;i<p.size();++i)
       {
                                         // Construct interpolation formula
@@ -694,20 +658,30 @@ namespace Polynomials
              }
          }
       }
-
+    
     return p;
   }
-
+  
 
 // ------------------ class Legendre --------------- //
 
 
+//TODO:[?] This class leaks memory, but only at the very end of a program.
+// Since it expands the Legendre<number>::coefficients array, the elements
+// of this static variable are not destroyed at the end of the program
+// run. While this is not a problem (since the returned memory could
+// not be used anyway then), it is a little confusing when looking at
+// a memory checker such as "purify". Maybe, this should be handled somehow
+// to avoid this confusion in future.
+
 // Reserve space for polynomials up to degree 19. Should be sufficient
 // for the start.
-  std::vector<std_cxx1x::shared_ptr<const std::vector<double> > >
-  Legendre::recursive_coefficients(20);
-  std::vector<std_cxx1x::shared_ptr<const std::vector<double> > >
-  Legendre::shifted_coefficients(20);
+  std::vector<const std::vector<double> *>
+  Legendre::recursive_coefficients(20,
+                                  static_cast<const std::vector<double>*>(0));
+  std::vector<const std::vector<double> *>
+  Legendre::shifted_coefficients(20,
+                                static_cast<const std::vector<double>*>(0));
 
 
   Legendre::Legendre (const unsigned int k)
@@ -716,7 +690,7 @@ namespace Polynomials
   {}
 
 
-
+  
   void
   Legendre::compute_coefficients (const unsigned int k_)
   {
@@ -730,7 +704,7 @@ namespace Polynomials
 #else
     typedef long double SHIFT_TYPE;
 #endif
-
+    
     unsigned int k = k_;
 
                                      // first make sure that no other
@@ -747,13 +721,12 @@ namespace Polynomials
                                      // already exist?
     if ((recursive_coefficients.size() < k+1) ||
         ((recursive_coefficients.size() >= k+1) &&
-         (recursive_coefficients[k] ==
-         std_cxx1x::shared_ptr<const std::vector<double> >())))
+         (recursive_coefficients[k] == 0)))
                                        // no, then generate the
                                        // respective coefficients
       {
-        recursive_coefficients.resize (k+1);
-
+        recursive_coefficients.resize (k+1, 0);
+      
         if (k<=1)
           {
                                              // create coefficients
@@ -772,28 +745,21 @@ namespace Polynomials
             (*c1)[1] = 1.;
 
                                              // now make these arrays
-                                             // const. use shared_ptr for
-                                             // recursive_coefficients because
-                                             // that avoids a memory leak that
-                                             // would appear if we used plain
-                                             // pointers.
-           recursive_coefficients[0] =
-             std_cxx1x::shared_ptr<const std::vector<double> >(c0);
-           recursive_coefficients[1] =
-             std_cxx1x::shared_ptr<const std::vector<double> >(c1);
-
+                                             // const
+            recursive_coefficients[0] = c0;
+            recursive_coefficients[1] = c1;
                                              // Compute polynomials
                                              // orthogonal on [0,1]
             c0 = new std::vector<double>(*c0);
             c1 = new std::vector<double>(*c1);
-
+         
             Polynomial<double>::shift<SHIFT_TYPE> (*c0, -1.);
             Polynomial<double>::scale(*c0, 2.);
             Polynomial<double>::shift<SHIFT_TYPE> (*c1, -1.);
             Polynomial<double>::scale(*c1, 2.);
             Polynomial<double>::multiply(*c1, std::sqrt(3.));
-            shifted_coefficients[0]=std_cxx1x::shared_ptr<const std::vector<double> >(c0);
-            shifted_coefficients[1]=std_cxx1x::shared_ptr<const std::vector<double> >(c1);
+            shifted_coefficients[0]=c0;
+            shifted_coefficients[1]=c1;
           }
         else
           {
@@ -810,11 +776,11 @@ namespace Polynomials
             coefficients_lock.acquire ();
 
             std::vector<double> *ck = new std::vector<double>(k+1);
-
+         
             const double a = 1./(k);
             const double b = a*(2*k-1);
             const double c = a*(k-1);
-
+         
             (*ck)[k]   = b*(*recursive_coefficients[k-1])[k-1];
             (*ck)[k-1] = b*(*recursive_coefficients[k-1])[k-2];
             for (unsigned int i=1 ; i<= k-2 ; ++i)
@@ -827,16 +793,14 @@ namespace Polynomials
                                              // created vector to the
                                              // const pointer in the
                                              // coefficients array
-            recursive_coefficients[k] =
-             std_cxx1x::shared_ptr<const std::vector<double> >(ck);
+            recursive_coefficients[k] = ck;
                                              // and compute the
                                              // coefficients for [0,1]
             ck = new std::vector<double>(*ck);
             Polynomial<double>::shift<SHIFT_TYPE> (*ck, -1.);
             Polynomial<double>::scale(*ck, 2.);
             Polynomial<double>::multiply(*ck, std::sqrt(2.*k+1.));
-            shifted_coefficients[k] =
-             std_cxx1x::shared_ptr<const std::vector<double> >(ck);
+            shifted_coefficients[k] = ck;
           };
       };
   }
@@ -870,6 +834,81 @@ namespace Polynomials
   }
 
 
+// ------------------ class Lobatto -------------------- //
+
+
+Lobatto::Lobatto (const unsigned int p) : Polynomial<double> (compute_coefficients (p)) {
+}
+
+std::vector<double> Lobatto::compute_coefficients (const unsigned int p) {
+   switch (p) {
+      case 0: {
+         std::vector<double> coefficients (2);
+
+         coefficients[0] = 1.0;
+         coefficients[1] = -1.0;
+         return coefficients;
+      }
+
+      case 1: {
+         std::vector<double> coefficients (2);
+
+         coefficients[0] = 0.0;
+         coefficients[1] = 1.0;
+         return coefficients;
+      }
+
+      case 2: {
+         std::vector<double> coefficients (3);
+
+         coefficients[0] = 0.0;
+         coefficients[1] = -1.0 * std::sqrt (3);
+         coefficients[2] = std::sqrt (3);
+         return coefficients;
+      }
+
+      default: {
+         std::vector<double> coefficients (p + 1);
+         std::vector<double> legendre_coefficients_tmp1 (p);
+         std::vector<double> legendre_coefficients_tmp2 (p - 1);
+
+         coefficients[0] = -1.0 * std::sqrt (3);
+         coefficients[1] = 2.0 * std::sqrt (3);
+         legendre_coefficients_tmp1[0] = 1.0;
+
+         for (unsigned int i = 2; i < p; ++i) {
+            for (unsigned int j = 0; j < i - 1; ++j)
+               legendre_coefficients_tmp2[j] = legendre_coefficients_tmp1[j];
+
+            for (unsigned int j = 0; j < i; ++j)
+               legendre_coefficients_tmp1[j] = coefficients[j];
+
+            coefficients[0] = std::sqrt (2 * i + 1) * ((1.0 - 2 * i) * legendre_coefficients_tmp1[0] / std::sqrt (2 * i - 1) + (1.0 - i) * legendre_coefficients_tmp2[0] / std::sqrt (2 * i - 3)) / i;
+
+            for (unsigned int j = 1; j < i - 1; ++j)
+               coefficients[j] = std::sqrt (2 * i + 1) * (std::sqrt (2 * i - 1) * (2.0 * legendre_coefficients_tmp1[j - 1] - legendre_coefficients_tmp1[j]) + (1.0 - i) * legendre_coefficients_tmp2[j] / std::sqrt (2 * i - 3)) / i;
+
+            coefficients[i - 1] = std::sqrt (4 * i * i - 1) * (2.0 * legendre_coefficients_tmp1[i - 2] - legendre_coefficients_tmp1[i - 1]) / i;
+            coefficients[i] = 2.0 * std::sqrt (4 * i * i - 1) * legendre_coefficients_tmp1[i - 1] / i;
+         }
+
+         for (int i = p; i > 0; --i)
+            coefficients[i] = coefficients[i - 1] / i;
+
+         coefficients[0] = 0.0;
+         return coefficients;
+      }
+   }
+}
+
+std::vector<Polynomial<double> > Lobatto::generate_complete_basis (const unsigned int p) {
+   std::vector<Polynomial<double> > basis (p + 1);
+
+   for (unsigned int i = 0; i <= p; ++i)
+      basis[i] = Lobatto (i);
+
+   return basis;
+}
 
 // ------------------ class Hierarchical --------------- //
 
@@ -902,20 +941,20 @@ namespace Polynomials
                                      // until we quit this function
     Threads::ThreadMutex::ScopedLock lock(coefficients_lock);
 
-                                     // The first 2 coefficients
+                                     // The first 2 coefficients 
                                      // are hard-coded
     if (k==0)
       k=1;
                                      // check: does the information
                                      // already exist?
     if (  (recursive_coefficients.size() < k+1) ||
-         ((recursive_coefficients.size() >= k+1) &&
+         ((recursive_coefficients.size() >= k+1) && 
            (recursive_coefficients[k] == 0)) )
                                           // no, then generate the
                                           // respective coefficients
       {
        recursive_coefficients.resize (k+1, 0);
-
+      
        if (k<=1)
          {
                                              // create coefficients
@@ -952,7 +991,7 @@ namespace Polynomials
            (*c2)[0] =   0.*a;
            (*c2)[1] =  -4.*a;
            (*c2)[2] =   4.*a;
-
+           
            recursive_coefficients[2] = c2;
          }
        else
@@ -970,15 +1009,15 @@ namespace Polynomials
            coefficients_lock.acquire ();
 
            std::vector<double> *ck = new std::vector<double>(k+1);
-
+          
            const double a = 1.; //1./(2.*k);
 
            (*ck)[0] = - a*(*recursive_coefficients[k-1])[0];
-
+         
            for (unsigned int i=1; i<=k-1; ++i)
                (*ck)[i] = a*( 2.*(*recursive_coefficients[k-1])[i-1]
                               - (*recursive_coefficients[k-1])[i] );
-
+         
            (*ck)[k] = a*2.*(*recursive_coefficients[k-1])[k-1];
                                          // for even degrees, we need
                                          // to add a multiple of
@@ -991,7 +1030,7 @@ namespace Polynomials
 
                (*ck)[1] += b*(*recursive_coefficients[2])[1];
                (*ck)[2] += b*(*recursive_coefficients[2])[2];
-             }
+             }   
                                              // finally assign the newly
                                              // created vector to the
                                              // const pointer in the
diff --git a/deal.II/base/source/polynomials_nedelec.cc b/deal.II/base/source/polynomials_nedelec.cc
new file mode 100644 (file)
index 0000000..24c76b9
--- /dev/null
@@ -0,0 +1,496 @@
+#include <base/geometry_info.h>
+#include <base/quadrature_lib.h>
+#include <base/polynomial.h>
+#include <base/polynomials_nedelec.h>
+#include <iostream>
+#include <iomanip>
+
+DEAL_II_NAMESPACE_OPEN
+
+
+template<int dim>
+PolynomialsNedelec<dim>::PolynomialsNedelec (const unsigned int k) : my_degree (k), polynomial_space (create_polynomials (k)), n_pols (compute_n_pols (k)) {
+}
+
+template<int dim>
+std::vector<std::vector< Polynomials::Polynomial<double> > > PolynomialsNedelec<dim>::create_polynomials (const unsigned int k) {
+   std::vector<std::vector< Polynomials::Polynomial<double> > > pols (dim);
+
+   pols[0] = Polynomials::Legendre::generate_complete_basis (k);
+
+   for (unsigned int i = 1; i < dim; ++i)
+      pols[i] = Polynomials::Lobatto::generate_complete_basis (k + 1);
+
+   return pols;
+}
+
+
+template<int dim>
+void PolynomialsNedelec<dim>::compute (const Point<dim> &unit_point, std::vector<Tensor<1,dim> > &values, std::vector<Tensor<2,dim> > &grads, std::vector<Tensor<3,dim> > &grad_grads) const {
+   Assert(values.size () == n_pols || values.size () == 0, ExcDimensionMismatch(values.size (), n_pols));
+   Assert(grads.size () == n_pols || grads.size () == 0, ExcDimensionMismatch(grads.size (), n_pols));
+   Assert(grad_grads.size () == n_pols || grad_grads.size () == 0, ExcDimensionMismatch(grad_grads.size (), n_pols));
+   // Declare the values, derivatives and second derivatives vectors of <tt>polynomial_space</tt> at <tt>unit_point</tt>
+   const unsigned int n_basis = polynomial_space.n ();
+   std::vector<double> unit_point_values ((values.size () == 0) ? 0 : n_basis);
+   std::vector<Tensor<1, dim> > unit_point_grads ((grads.size () == 0) ? 0 : n_basis);
+   std::vector<Tensor<2, dim> > unit_point_grad_grads ((grad_grads.size () == 0) ? 0 : n_basis);
+
+   switch (dim) {
+      case 1: {
+         polynomial_space.compute (unit_point, unit_point_values, unit_point_grads, unit_point_grad_grads);
+         // Assign the correct values to the corresponding shape functions.
+         if (values.size () > 0)
+            for (unsigned int i = 0; i < unit_point_values.size (); ++i)
+               values[i][0] = unit_point_values[i];
+
+         if (grads.size () > 0)
+            for (unsigned int i = 0; i < unit_point_grads.size (); ++i)
+               grads[i][0][0] = unit_point_grads[i][0];
+
+         if (grad_grads.size () > 0)
+            for (unsigned int i = 0; i < unit_point_grad_grads.size (); ++i)
+               grad_grads[i][0][0][0] = unit_point_grad_grads[i][0][0];
+
+         break;
+      }
+
+      case 2: {
+         polynomial_space.compute (unit_point, unit_point_values, unit_point_grads, unit_point_grad_grads);
+         // Declare the values, derivatives and second derivatives vectors of <tt>polynomial_space</tt> at <tt>unit_point</tt> with coordinates
+         // shifted one step in positive direction
+         Point<dim> p;
+         std::vector<double> p_values ((values.size () == 0) ? 0 : n_basis);
+         std::vector<Tensor<1, dim> > p_grads ((grads.size () == 0) ? 0 : n_basis);
+         std::vector<Tensor<2, dim> > p_grad_grads ((grad_grads.size () == 0) ? 0 : n_basis);
+
+         p (0) = unit_point (1);
+         p (1) = unit_point (0);
+         polynomial_space.compute (p, p_values, p_grads, p_grad_grads);
+         // Assign the correct values to the corresponding shape functions.
+         if (values.size () > 0) {
+            for (unsigned int i = 0; i <= my_degree; ++i)
+               for (unsigned int j = 0; j < 2; ++j) {
+                  values[i + j * (my_degree + 1)][0] = 0.0;
+                  values[i + j * (my_degree + 1)][1] = p_values[i + j * (my_degree + 1)];
+                  values[i + (j + 2) * (my_degree + 1)][0] = unit_point_values[i + j * (my_degree + 1)];
+                  values[i + (j + 2) * (my_degree + 1)][1] = 0.0;
+               }
+
+            if (my_degree > 0)
+               for (unsigned int i = 0; i <= my_degree; ++i)
+                  for (unsigned int j = 0; j < my_degree; ++j) {
+                     values[(i + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][0] = unit_point_values[i + (j + 2) * (my_degree + 1)];
+                     values[(i + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1] = 0.0;
+                     values[i + (j + my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][0] = 0.0;
+                     values[i + (j + my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1] = p_values[i + (j + 2) * (my_degree + 1)];
+                  }
+         }
+
+         if (grads.size () > 0) {
+            for (unsigned int i = 0; i <= my_degree; ++i)
+               for (unsigned int j = 0; j < 2; ++j) {
+                  for (unsigned int k = 0; k < dim; ++k) {
+                     grads[i + j * (my_degree + 1)][0][k] = 0.0;
+                     grads[i + (j + 2) * (my_degree + 1)][0][k] = unit_point_grads[i + j * (my_degree + 1)][k];
+                     grads[i + (j + 2) * (my_degree + 1)][1][k] = 0.0;
+                  }
+                  
+                  grads[i + j * (my_degree + 1)][1][0] = p_grads[i + j * (my_degree + 1)][1];
+                  grads[i + j * (my_degree + 1)][1][1] = p_grads[i + j * (my_degree + 1)][0];
+               }
+
+            if (my_degree > 0)
+               for (unsigned int i = 0; i <= my_degree; ++i)
+                  for (unsigned int j = 0; j < my_degree; ++j) {
+                     for (unsigned int k = 0; k < dim; ++k) {
+                        grads[(i + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][0][k] = unit_point_grads[i + (j + 2) * (my_degree + 1)][k];
+                        grads[(i + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][k] = 0.0;
+                        grads[i + (j + my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][0][k] = 0.0;
+                     }
+                     
+                     grads[i + (j + my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][0] = p_grads[i + (j + 2) * (my_degree + 1)][1];
+                     grads[i + (j + my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][1] = p_grads[i + (j + 2) * (my_degree + 1)][0];
+                  }
+         }
+
+         if (grad_grads.size () > 0) {
+            for (unsigned int i = 0; i <= my_degree; ++i)
+               for (unsigned int j = 0; j < 2; ++j) {
+                  for (unsigned int k = 0; k < dim; ++k)
+                     for (unsigned int l = 0; l < dim; ++l) {
+                        grad_grads[i + j * (my_degree + 1)][0][k][l] = 0.0;
+                        grad_grads[i + (j + 2) * (my_degree + 1)][0][k][l] = unit_point_grad_grads[i + l * (my_degree + 1)][k][l];
+                        grad_grads[i + (j + 2) * (my_degree + 1)][1][k][l] = 0.0;
+                     }
+                  
+                  grad_grads[i + j * (my_degree + 1)][1][0][0] = p_grad_grads[i + j * (my_degree + 1)][1][1];
+                  grad_grads[i + j * (my_degree + 1)][1][0][1] = p_grad_grads[i + j * (my_degree + 1)][1][0];
+                  grad_grads[i + j * (my_degree + 1)][1][1][0] = p_grad_grads[i + j * (my_degree + 1)][0][1];
+                  grad_grads[i + j * (my_degree + 1)][1][1][1] = p_grad_grads[i + j * (my_degree + 1)][0][0];
+               }
+
+            if (my_degree > 0)
+               for (unsigned int i = 0; i <= my_degree; ++i)
+                  for (unsigned int j = 0; j < my_degree; ++j) {
+                     for (unsigned int k = 0; k < dim; ++k)
+                        for (unsigned int l = 0; l < dim; ++l) {
+                           grad_grads[(i + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][0][k][l] = unit_point_grad_grads[i + (j + 2) * (my_degree + 1)][k][l];
+                           grad_grads[(i + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][k][l] = 0.0;
+                           grad_grads[i + (j + my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][0][k][l] = 0.0;
+                        }
+                        
+                     grad_grads[i + (j + my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][0][0] = p_grad_grads[i + (j + 2) * (my_degree + 1)][1][1];
+                     grad_grads[i + (j + my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][0][1] = p_grad_grads[i + (j + 2) * (my_degree + 1)][1][0];
+                     grad_grads[i + (j + my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][1][0] = p_grad_grads[i + (j + 2) * (my_degree + 1)][0][1];
+                     grad_grads[i + (j + my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][1][1] = p_grad_grads[i + (j + 2) * (my_degree + 1)][0][0];
+                  }
+         }
+
+         break;
+      }
+
+      case 3: {
+         polynomial_space.compute (unit_point, unit_point_values, unit_point_grads, unit_point_grad_grads);
+         // Declare the values, derivatives and second derivatives vectors of <tt>polynomial_space</tt> at <tt>unit_point</tt> with coordinates
+         // shifted two steps in positive direction
+         Point<dim> p1, p2;
+         std::vector<double> p1_values ((values.size () == 0) ? 0 : n_basis);
+         std::vector<Tensor<1, dim> > p1_grads ((grads.size () == 0) ? 0 : n_basis);
+         std::vector<Tensor<2, dim> > p1_grad_grads ((grad_grads.size () == 0) ? 0 : n_basis);
+         std::vector<double> p2_values ((values.size () == 0) ? 0 : n_basis);
+         std::vector<Tensor<1, dim> > p2_grads ((grads.size () == 0) ? 0 : n_basis);
+         std::vector<Tensor<2, dim> > p2_grad_grads ((grad_grads.size () == 0) ? 0 : n_basis);
+
+         p1 (0) = unit_point (1);
+         p1 (1) = unit_point (2);
+         p1 (2) = unit_point (0);
+         polynomial_space.compute (p1, p1_values, p1_grads, p1_grad_grads);
+         p2 (0) = unit_point (2);
+         p2 (1) = unit_point (0);
+         p2 (2) = unit_point (1);
+         polynomial_space.compute (p2, p2_values, p2_grads, p2_grad_grads);
+         // Assign the correct values to the corresponding shape functions.
+         if (values.size () > 0) {
+            for (unsigned int i = 0; i <= my_degree; ++i) {
+               for (unsigned int j = 0; j < 2; ++j) {
+                  for (unsigned int k = 0; k < 2; ++k) {
+                     for (unsigned int l = 0; l < 2; ++l) {
+                        values[i + (j + 4 * k) * (my_degree + 1)][2 * l] = 0;
+                        values[i + (j + 4 * k + 2) * (my_degree + 1)][l + 1] = 0;
+                        values[i + (j + 2 * (k + 4)) * (my_degree + 1)][l] = 0;
+                     }
+
+                     values[i + (j + 4 * k + 2) * (my_degree + 1)][0] = unit_point_values[i + (j + k * (my_degree + 2)) * (my_degree + 1)];
+                     values[i + (j + 2 * (k + 4)) * (my_degree + 1)][2] = p2_values[i + (j + k * (my_degree + 2)) * (my_degree + 1)];
+                  }
+
+                  values[i + j * (my_degree + 1)][1] = p1_values[i + j * (my_degree + 1) * (my_degree + 2)];
+               }
+
+               values[i + 4 * (my_degree + 1)][1] = p1_values[i + my_degree + 1];
+               values[i + 5 * (my_degree + 1)][1] = p1_values[i + (my_degree + 1) * (my_degree + 3)];
+            }
+
+            if (my_degree > 0)
+               for (unsigned int i = 0; i <= my_degree; ++i)
+                  for (unsigned int j = 0; j < my_degree; ++j) {
+                     for (unsigned int k = 0; k < my_degree; ++k) {
+                        for (unsigned int l = 0; l < 2; ++l) {
+                           values[((i + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][l + 1] = 0;
+                           values[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][2 * l] = 0;
+                           values[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][l] = 0;
+                        }
+
+                        values[((i + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][0] = unit_point_values[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)];
+                        values[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1] = p1_values[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)];
+                        values[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2] = p2_values[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)];
+                     }
+
+                     for (unsigned int k = 0; k < 2; ++k) {
+                        for (unsigned int l = 0; l < 2; ++l) {
+                           for (unsigned int m = 0; m < 2; ++m) {
+                              values[i + (j + (2 * (k + 2 * l) + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][m] = 0;
+                              values[(i + 2 * (k + 2 * (l + 1)) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][m + 1] = 0;
+                           }
+
+                           values[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][2 * l] = 0;
+                           values[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2 * l] = 0;
+                        }
+
+                        values[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1] = p1_values[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)];
+                        values[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2] = p2_values[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)];
+                        values[(i + 2 * (k + 2) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][0] = unit_point_values[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)];
+                        values[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2] = p2_values[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)];
+                        values[(i + 2 * (k + 4) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][0] = unit_point_values[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)];
+                        values[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1] = p1_values[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)];
+                     }
+                  }
+         }
+
+         if (grads.size () > 0) {
+            for (unsigned int i = 0; i <= my_degree; ++i) {
+               for (unsigned int j = 0; j < 2; ++j) {
+                  for (unsigned int k = 0; k < 2; ++k) {
+                     for (unsigned int l = 0; l < 2; ++l)
+                        for (unsigned int m = 0; m < dim; ++m) {
+                           grads[i + (j + 4 * k) * (my_degree + 1)][2 * l][m] = 0;
+                           grads[i + (j + 4 * k + 2) * (my_degree + 1)][l + 1][m] = 0;
+                           grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][l][m] = 0;
+                        }
+
+                     for (unsigned int l = 0; l < dim; ++l)
+                        grads[i + (j + 4 * k + 2) * (my_degree + 1)][0][l] = unit_point_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][l];
+                        
+                     grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][0] = p2_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][1];
+                     grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][1] = p2_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][2];
+                     grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][2] = p2_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][0];
+                  }
+
+                  grads[i + j * (my_degree + 1)][1][0] = p1_grads[i + j * (my_degree + 1) * (my_degree + 2)][2];
+                  grads[i + j * (my_degree + 1)][1][1] = p1_grads[i + j * (my_degree + 1) * (my_degree + 2)][0];
+                  grads[i + j * (my_degree + 1)][1][2] = p1_grads[i + j * (my_degree + 1) * (my_degree + 2)][1];
+               }
+
+               grads[i + 4 * (my_degree + 1)][1][0] = p1_grads[i + my_degree + 1][2];
+               grads[i + 4 * (my_degree + 1)][1][1] = p1_grads[i + my_degree + 1][0];
+               grads[i + 4 * (my_degree + 1)][1][2] = p1_grads[i + my_degree + 1][1];
+               grads[i + 5 * (my_degree + 1)][1][0] = p1_grads[i + (my_degree + 1) * (my_degree + 3)][2];
+               grads[i + 5 * (my_degree + 1)][1][1] = p1_grads[i + (my_degree + 1) * (my_degree + 3)][0];
+               grads[i + 5 * (my_degree + 1)][1][2] = p1_grads[i + (my_degree + 1) * (my_degree + 3)][1];
+            }
+
+            if (my_degree > 0)
+               for (unsigned int i = 0; i <= my_degree; ++i)
+                  for (unsigned int j = 0; j < my_degree; ++j) {
+                     for (unsigned int k = 0; k < my_degree; ++k) {
+                        for (unsigned int l = 0; l < dim; ++l) {
+                           for (unsigned int m = 0; m < 2; ++m) {
+                              grads[((i + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][m + 1][l] = 0;
+                              grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][2 * m][l] = 0;
+                              grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][m][l] = 0;
+                           }
+
+                           grads[((i + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][0][l] = unit_point_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][l];
+                        }
+                           
+                        grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][0] = p1_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][2];
+                        grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][1] = p1_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][0];
+                        grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][2] = p1_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][1];
+                        grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0] = p2_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][1];
+                        grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1] = p2_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][2];
+                        grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2] = p2_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][0];
+                     }
+
+                     for (unsigned int k = 0; k < 2; ++k) {
+                        for (unsigned int l = 0; l < 2; ++l)
+                           for (unsigned int m = 0; m < dim; ++m) {
+                                 for (unsigned int n = 0; n < 2; ++n) {
+                                 grads[i + (j + (2 * (k + 2 * l) + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][n][m] = 0;
+                                 grads[(i + 2 * (k + 2 * (l + 1)) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][n + 1][m] = 0;
+                              }
+
+                              grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][2 * l][m] = 0;
+                              grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2 * l][m] = 0;
+                           }
+
+                        for (unsigned int l = 0; l < dim; ++l) {
+                           grads[(i + 2 * (k + 2) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][0][l] = unit_point_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][l];
+                           grads[(i + 2 * (k + 4) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][0][l] = unit_point_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][l];
+                        }
+
+                        grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][0] = p1_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][2];
+                        grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][1] = p1_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][0];
+                        grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][2] = p1_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][1];
+                        grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0] = p2_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][1];
+                        grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1] = p2_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][2];
+                        grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2] = p2_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][0];
+                        grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0] = p2_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][1];
+                        grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1] = p2_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][2];
+                        grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2] = p2_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][0];
+                        grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][0] = p1_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][1];
+                        grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][1] = p1_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][2];
+                        grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][2] = p1_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][0];
+                     }
+                  }
+         }
+
+         if (grad_grads.size () > 0) {
+            for (unsigned int i = 0; i <= my_degree; ++i) {
+               for (unsigned int j = 0; j < 2; ++j) {
+                  for (unsigned int k = 0; k < 2; ++k) {
+                     for (unsigned int l = 0; l < dim; ++l)
+                        for (unsigned int m = 0; m < dim; ++m) {
+                           for (unsigned int n = 0; n < 2; ++n) {
+                              grad_grads[i + (j + 4 * k) * (my_degree + 1)][2 * n][l][m] = 0;
+                              grad_grads[i + (j + 4 * k + 2) * (my_degree + 1)][n + 1][l][m] = 0;
+                              grad_grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][n][l][m] = 0;
+                           }
+
+                           grad_grads[i + (j + 4 * k + 2) * (my_degree + 1)][0][l][m] = unit_point_grad_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][l][m];
+                        }
+                     
+                     grad_grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][0][0] = p2_grad_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][1][1];
+                     grad_grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][0][1] = p2_grad_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][1][2];
+                     grad_grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][0][2] = p2_grad_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][1][0];
+                     grad_grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][1][0] = p2_grad_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][2][1];
+                     grad_grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][1][1] = p2_grad_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][2][2];
+                     grad_grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][1][2] = p2_grad_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][2][0];
+                     grad_grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][2][0] = p2_grad_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][0][1];
+                     grad_grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][2][1] = p2_grad_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][0][2];
+                     grad_grads[i + (j + 2 * (k + 4)) * (my_degree + 1)][2][2][2] = p2_grad_grads[i + (j + k * (my_degree + 2)) * (my_degree + 1)][0][0];
+                  }
+
+                  grad_grads[i + j * (my_degree + 1)][1][0][0] = p1_grad_grads[i + j * (my_degree + 1) * (my_degree + 2)][2][2];
+                  grad_grads[i + j * (my_degree + 1)][1][0][1] = p1_grad_grads[i + j * (my_degree + 1) * (my_degree + 2)][2][0];
+                  grad_grads[i + j * (my_degree + 1)][1][0][2] = p1_grad_grads[i + j * (my_degree + 1) * (my_degree + 2)][2][1];
+                  grad_grads[i + j * (my_degree + 1)][1][1][0] = p1_grad_grads[i + j * (my_degree + 1) * (my_degree + 2)][0][2];
+                  grad_grads[i + j * (my_degree + 1)][1][1][1] = p1_grad_grads[i + j * (my_degree + 1) * (my_degree + 2)][0][0];
+                  grad_grads[i + j * (my_degree + 1)][1][1][2] = p1_grad_grads[i + j * (my_degree + 1) * (my_degree + 2)][0][1];
+                  grad_grads[i + j * (my_degree + 1)][1][2][0] = p1_grad_grads[i + j * (my_degree + 1) * (my_degree + 2)][1][2];
+                  grad_grads[i + j * (my_degree + 1)][1][2][1] = p1_grad_grads[i + j * (my_degree + 1) * (my_degree + 2)][1][0];
+                  grad_grads[i + j * (my_degree + 1)][1][2][2] = p1_grad_grads[i + j * (my_degree + 1) * (my_degree + 2)][1][1];
+               }
+
+               grad_grads[i + 4 * (my_degree + 1)][1][0][0] = p1_grad_grads[i + my_degree + 1][2][2];
+               grad_grads[i + 4 * (my_degree + 1)][1][0][1] = p1_grad_grads[i + my_degree + 1][2][0];
+               grad_grads[i + 4 * (my_degree + 1)][1][0][2] = p1_grad_grads[i + my_degree + 1][2][1];
+               grad_grads[i + 4 * (my_degree + 1)][1][1][0] = p1_grad_grads[i + my_degree + 1][0][2];
+               grad_grads[i + 4 * (my_degree + 1)][1][1][1] = p1_grad_grads[i + my_degree + 1][0][0];
+               grad_grads[i + 4 * (my_degree + 1)][1][1][2] = p1_grad_grads[i + my_degree + 1][0][1];
+               grad_grads[i + 4 * (my_degree + 1)][1][2][0] = p1_grad_grads[i + my_degree + 1][1][2];
+               grad_grads[i + 4 * (my_degree + 1)][1][2][1] = p1_grad_grads[i + my_degree + 1][1][0];
+               grad_grads[i + 4 * (my_degree + 1)][1][2][2] = p1_grad_grads[i + my_degree + 1][1][1];
+               grad_grads[i + 5 * (my_degree + 1)][1][0][0] = p1_grad_grads[i + (my_degree + 1) * (my_degree + 3)][2][2];
+               grad_grads[i + 5 * (my_degree + 1)][1][0][1] = p1_grad_grads[i + (my_degree + 1) * (my_degree + 3)][2][0];
+               grad_grads[i + 5 * (my_degree + 1)][1][0][2] = p1_grad_grads[i + (my_degree + 1) * (my_degree + 3)][2][1];
+               grad_grads[i + 5 * (my_degree + 1)][1][1][0] = p1_grad_grads[i + (my_degree + 1) * (my_degree + 3)][0][2];
+               grad_grads[i + 5 * (my_degree + 1)][1][1][1] = p1_grad_grads[i + (my_degree + 1) * (my_degree + 3)][0][0];
+               grad_grads[i + 5 * (my_degree + 1)][1][1][2] = p1_grad_grads[i + (my_degree + 1) * (my_degree + 3)][0][1];
+               grad_grads[i + 5 * (my_degree + 1)][1][2][0] = p1_grad_grads[i + (my_degree + 1) * (my_degree + 3)][1][2];
+               grad_grads[i + 5 * (my_degree + 1)][1][2][1] = p1_grad_grads[i + (my_degree + 1) * (my_degree + 3)][1][0];
+               grad_grads[i + 5 * (my_degree + 1)][1][2][2] = p1_grad_grads[i + (my_degree + 1) * (my_degree + 3)][1][1];
+            }
+
+            if (my_degree > 0)
+               for (unsigned int i = 0; i <= my_degree; ++i)
+                  for (unsigned int j = 0; j < my_degree; ++j) {
+                     for (unsigned int k = 0; k < my_degree; ++k) {
+                        for (unsigned int l = 0; l < dim; ++l)
+                           for (unsigned int m = 0; m < dim; ++m) {
+                              for (unsigned int n = 0; n < 2; ++n) {
+                                 grad_grads[((i + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][n + 1][l][m] = 0;
+                                 grad_grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][2 * n][l][m] = 0;
+                                 grad_grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][n][l][m] = 0;
+                              }
+
+                              grad_grads[((i + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell + 2 * GeometryInfo<dim>::faces_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][0][l][m] = unit_point_grad_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][l][m];
+                           }
+                           
+                        grad_grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][0][0] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][2][2];
+                        grad_grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][0][1] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][2][0];
+                        grad_grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][0][2] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][2][1];
+                        grad_grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][1][0] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][0][2];
+                        grad_grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][1][1] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][0][0];
+                        grad_grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][1][2] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][0][1];
+                        grad_grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][2][0] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][1][2];
+                        grad_grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][2][1] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][1][0];
+                        grad_grads[(i + (j + 2 * GeometryInfo<dim>::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + k + GeometryInfo<dim>::lines_per_cell][1][2][2] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][1][1];
+                        grad_grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0][0] = p2_grad_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][1][1];
+                        grad_grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0][1] = p2_grad_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][1][2];
+                        grad_grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0][2] = p2_grad_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][1][0];
+                        grad_grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1][0] = p2_grad_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][2][1];
+                        grad_grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1][1] = p2_grad_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][2][2];
+                        grad_grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1][2] = p2_grad_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][2][0];
+                        grad_grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2][0] = p2_grad_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][0][1];
+                        grad_grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2][1] = p2_grad_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][0][2];
+                        grad_grads[i + (j + (k + 2 * (GeometryInfo<dim>::faces_per_cell + my_degree)) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2][2] = p2_grad_grads[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)][0][0];
+                     }
+
+                     for (unsigned int k = 0; k < 2; ++k) {
+                        for (unsigned int l = 0; l < dim; ++l)
+                           for (unsigned int m = 0; m < dim; ++m) {
+                              for (unsigned int n = 0; n < 2; ++n) {
+                                 for (unsigned int o = 0; o < 2; ++o) {
+                                    grad_grads[i + (j + (2 * (k + 2 * n) + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][o][l][m] = 0;
+                                    grad_grads[(i + 2 * (k + 2 * (n + 1)) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][o + 1][l][m] = 0;
+                                 }
+
+                                 grad_grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][2 * n][l][m] = 0;
+                                 grad_grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2 * n][l][m] = 0;
+                              }
+                              
+                              grad_grads[(i + 2 * (k + 2) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][0][l][m] = unit_point_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][l][m];
+                              grad_grads[(i + 2 * (k + 4) * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][0][l][m] = unit_point_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][l][m];
+                           }
+
+                        grad_grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][0][0] = p1_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][2][2];
+                        grad_grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][0][1] = p1_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][2][0];
+                        grad_grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][0][2] = p1_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][2][1];
+                        grad_grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][1][0] = p1_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][0][2];
+                        grad_grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][1][1] = p1_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][0][0];
+                        grad_grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][1][2] = p1_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][0][1];
+                        grad_grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][2][0] = p1_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][1][2];
+                        grad_grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][2][1] = p1_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][1][0];
+                        grad_grads[(i + 2 * k * (my_degree + 1) + GeometryInfo<dim>::lines_per_cell) * my_degree + j + GeometryInfo<dim>::lines_per_cell][1][2][2] = p1_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][1][1];
+                        grad_grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0][0] = p2_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][1][1];
+                        grad_grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0][1] = p2_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][1][2];
+                        grad_grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0][2] = p2_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][1][0];
+                        grad_grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1][0] = p2_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][2][1];
+                        grad_grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1][1] = p2_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][2][2];
+                        grad_grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1][2] = p2_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][2][0];
+                        grad_grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2][0] = p2_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][0][1];
+                        grad_grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2][1] = p2_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][0][2];
+                        grad_grads[i + (j + (2 * k + 1) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2][2] = p2_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][0][0];
+                        grad_grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0][0] = p2_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][1][1];
+                        grad_grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0][1] = p2_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][1][2];
+                        grad_grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][0][2] = p2_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][1][0];
+                        grad_grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1][0] = p2_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][2][1];
+                        grad_grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1][1] = p2_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][2][2];
+                        grad_grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][1][2] = p2_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][2][0];
+                        grad_grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2][0] = p2_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][0][1];
+                        grad_grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2][1] = p2_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][0][2];
+                        grad_grads[i + (j + (2 * k + 5) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][2][2][2] = p2_grad_grads[i + (j + k * (my_degree + 2) + 2) * (my_degree + 1)][0][0];
+                        grad_grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][0][0] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][2][2];
+                        grad_grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][0][1] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][2][0];
+                        grad_grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][0][2] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][2][1];
+                        grad_grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][1][0] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][0][2];
+                        grad_grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][1][1] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][0][0];
+                        grad_grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][1][2] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][0][1];
+                        grad_grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][2][0] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][1][2];
+                        grad_grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][2][1] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][1][0];
+                        grad_grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo<dim>::lines_per_cell) * (my_degree + 1)][1][2][2] = p1_grad_grads[i + ((j + 2) * (my_degree + 2) + k) * (my_degree + 1)][1][1];
+                     }
+                  }
+         }
+      }
+   }
+}
+
+
+template<int dim>
+unsigned int PolynomialsNedelec<dim>::compute_n_pols (unsigned int k) {
+   switch (dim) {
+      case 1:
+         return k + 1;
+
+      case 2:
+         return 2 * (k + 1) * (k + 2);
+
+      case 3:
+         return 3 * (k + 1) * (k + 2) * (k + 2);
+
+      default: {
+         Assert (false, ExcNotImplemented ());
+         return 0;
+      }
+   }
+}
+
+
+template class PolynomialsNedelec<1>;
+template class PolynomialsNedelec<2>;
+template class PolynomialsNedelec<3>;
+
+
+DEAL_II_NAMESPACE_CLOSE
index 47522137861006f55cde1418b7f1162d3e0a771e..80b24e752f244a6310dc0fe9631a3b5305b4a87f 100644 (file)
@@ -1,21 +1,17 @@
-//---------------------------------------------------------------------------
-//    $Id$
-//    Version: $Name$
-//
-//    Copyright (C) 2002, 2003, 2004, 2005, 2006 by the deal.II authors
-//
-//    This file is subject to QPL and may not be  distributed
-//    without copyright and license information. Please refer
-//    to the file deal.II/doc/license.html for the  text  and
-//    further information on this license.
-//
-//---------------------------------------------------------------------------
 #ifndef __deal2__fe_nedelec_h
 #define __deal2__fe_nedelec_h
 
 #include <base/config.h>
+#include <base/table.h>
+#include <base/tensor.h>
+#include <base/tensor_base.h>
+#include <base/polynomials_nedelec.h>
+#include <base/polynomial.h>
+#include <base/tensor_product_polynomials.h>
 #include <base/geometry_info.h>
 #include <fe/fe.h>
+#include <fe/fe_poly_tensor.h>
+#include <vector>
 
 DEAL_II_NAMESPACE_OPEN
 
@@ -26,173 +22,59 @@ template <int dim, int spacedim> class MappingQ;
 /*@{*/
 
 /**
- * Implementation of continuous Nedelec elements for the space
- * H_curl. Note, however, that continuity only concerns the tangential
- * component of the vector field.
+ * Implementation of Nédélec elements, conforming with the
+ * space H<sup>curl</sup>. These elements generate vector fields with
+ * tangential components continuous between mesh cells.
  *
- * The constructor of this class takes the degree @p p of this finite
- * element. However, presently, only lowest order elements
- * (i.e. <tt>p==1</tt>) are implemented. For a general overview of this
- * element and its properties, see the report by Anna Schneebeli that
- * is linked from the general documentation page of the library.
+ * We follow the usual definition of the degree of Nédélec elements,
+ * which denotes the polynomial degree of the lowest complete polynomial
+ * subspace contained in the Nédélec space. Then, approximation order of
+ * the function itself is <i>degree</i>.
  *
- * This class has not yet been implemented for the codimension one case
+ * This class is not implemented for the codimension one case
  * (<tt>spacedim != dim</tt>).
  *
+ * @todo Even if this element is implemented for two and three space
+ * dimensions, the definition of the node values relies on
+ * consistently oriented faces in 3D. Therefore, care should be taken
+ * on complicated meshes.
  *
- * <h3>Restriction on transformations</h3>
+ * <h3>Interpolation</h3>
  *
- * In some sense, the implementation of this element is not complete,
- * but you will rarely notice. Here is the fact: since the element is
- * vector-valued already on the unit cell, the Jacobian matrix (or its
- * inverse) is needed already to generate the values of the shape
- * functions on the cells in real space. This is in contrast to most
- * other elements, where you only need the Jacobian for the
- * gradients. Thus, to generate the gradients of Nedelec shape
- * functions, one would need to have the derivatives of the inverse of
- * the Jacobian matrix.
+ * The @ref GlossInterpolation "interpolation" operators associated
+ * with the Nédélec element are constructed such that interpolation and
+ * computing the curl are commuting operations. We require this
+ * from interpolating arbitrary functions as well as the #restriction
+ * matrices.
  *
- * Basically, the Nedelec shape functions can be understood as the
- * gradients of scalar shape functions on the real cell. They are thus
- * the inverse Jacobian matrix times the gradients of scalar shape
- * functions on the unit cell. The gradient of Nedelec shape functions
- * is then, by the product rule, the sum of first the derivative (with
- * respect to true coordinates) of the inverse Jacobian times the
- * gradient (in unit coordinates) of the scalar shape function, plus
- * second the inverse Jacobian times the derivative (in true
- * coordinates) of the gradient (in unit coordinates) of the scalar
- * shape functions. Note that each of the derivatives in true
- * coordinates can be expressed as inverse Jacobian times gradient in
- * unit coordinates.
+ * <h4>Node values</h4>
  *
- * The problem is the derivative of the inverse Jacobian. This rank-3
- * tensor can actually be computed (and we did so in very early
- * versions of the library), but is a large task and very time
- * consuming, so we dropped it. Since it is not available, we simply
- * drop this first term.
+ * The @ref GlossNodes "node values" on edges are the moments of the
+ * tangential component of the interpolated function with respect to
+ * the traces of the Nédélec polynomials. Higher-order Nédélec spaces
+ * also have face and interior nodes.
  *
- * What this means for the present case: first the computation of
- * gradients of Nedelec shape functions is wrong. Second, you will not
- * notice this usually, for two reasons:
+ * <h4>Generalized support points</h4>
  *
- * The first reason is that the gradient of the Jacobian vanishes if
- * the cells are mapped by an affine mapping, to which the usual
- * bilinear mapping reduces if the cell is a parallelogram. Then the
- * gradient of the shape functions is computed exact, since the first
- * term is zero.
+ * The node values above rely on integrals, which will be computed by
+ * quadrature rules themselves. The generalized support points are a
+ * set of points such that this quadrature can be performed with
+ * sufficient accuracy. The points needed are thode of
+ * QGauss<sub>k+1</sub> on each edge and QGauss<sub>k+2</sub> on each face and in
+ * the interior of the cell (or none for N<sub>1</sub>).
  *
- * Second, with the Nedelec elements, you will usually want to compute
- * the curl, and extract and sum up the respective elements of the
- * full gradient tensor. However, the curl of the Jacobian vanishes,
- * so for the curl of shape functions the first term is irrelevant,
- * and the curl will be computed correctly as well.
- * 
- * 
- * <h3>Interpolation to finer and coarser meshes</h3>
  *
- * Each finite element class in deal.II provides matrices that are
- * used to interpolate from coarser to finer meshes and the other way
- * round. Interpolation from a mother cell to its children is usually
- * trivial, since finite element spaces are normally nested and this
- * kind of interpolation is therefore exact. On the other hand, when
- * we interpolate from child cells to the mother cell, we usually have
- * to throw away some information.
- *
- * For continuous elements, this transfer usually happens by
- * interpolating the values on the child cells at the support points
- * of the shape functions of the mother cell. However, for
- * discontinuous elements, we often use a projection from the child
- * cells to the mother cell. The projection approach is only possible
- * for discontinuous elements, since it cannot be guaranteed that the
- * values of the projected functions on one cell and its neighbor
- * match. In this case, only an interpolation can be
- * used. (Internally, whether the values of a shape function are
- * interpolated or projected, or better: whether the matrices the
- * finite element provides are to be treated with the properties of a
- * projection or of an interpolation, is controlled by the
- * @p restriction_is_additive flag. See there for more information.)
- *
- * Here, things are not so simple: since the element has some
- * continuity requirements across faces, we can only resort to some
- * kind of interpolation. On the other hand, for the lowest order
- * elements, the values of generating functionals are the (constant)
- * tangential values of the shape functions. We would therefore really
- * like to take the mean value of the tangential values of the child
- * faces, and make this the value of the mother face. Then, however,
- * taking a mean value of two piecewise constant function is not an
- * interpolation, but a restriction. Since this is not possible, we
- * cannot use this.
- *
- * To make a long story somewhat shorter, when interpolating from
- * refined edges to a coarse one, we do not take the mean value, but
- * pick only one (the one from the first child edge). While this is
- * not optimal, it is certainly a valid choice (using an interpolation
- * point that is not in the middle of the cell, but shifted to one
- * side), and it also preserves the order of the interpolation.
- * 
- *
- * <h3>Numbering of the degrees of freedom (DoFs)</h3>
- *
- * Nedelec elements have their degrees of freedom on edges, with shape
- * functions being vector valued and pointing in tangential
- * direction. We use the standard enumeration and direction of edges
- * in deal.II, yielding the following shape functions in 2d:
- *
- *   @verbatim
- *       3
- *    2-->--3
- *    |     |
- *   0^     ^1
- *    |     |
- *    0-->--1
- *       2
- *   @endverbatim
- *
- * For the 3d case, the ordering follows the same scheme: the lines
- * are numbered as described in the documentation of the
- * Triangulation class, i.e.
- *   @verbatim
- *       *---7---*        *---7---*
- *      /|       |       /       /|
- *     4 |       11     4       5 11
- *    /  10      |     /       /  |
- *   *   |       |    *---6---*   |
- *   |   *---3---*    |       |   *
- *   |  /       /     |       9  /
- *   8 0       1      8       | 1
- *   |/       /       |       |/
- *   *---2---*        *---2---*
- *   @endverbatim
- * and their directions are as follows:
- *   @verbatim
- *         *--->---*        *--->---*
- *        /|       |       /       /|
- *       ^ |       ^      ^       ^ ^
- *      /  ^       |     /       /  |
- *     *   |       |    *--->---*   |
- *     |   *--->---*    |       |   *
- *     |  /       /     |       ^  /
- *     ^ ^       ^      ^       | ^
- *     |/       /       |       |/
- *     *--->---*        *--->---*
- *   @endverbatim
- *
- * The element does not make much sense in 1d, so it is not
- * implemented there.
- *
- *
- * @author Wolfgang Bangerth, Anna Schneebeli, 2002, 2003
+ * @author Markus Bürg, 2009
  */
-template <int dim, int spacedim=dim>
-class FE_Nedelec : public FiniteElement<dim,spacedim>
-{
-  public:
+template <int dim>
+class FE_Nedelec : public FE_PolyTensor<PolynomialsNedelec<dim>, dim> {
+   public:
                                     /**
-                                     * Constructor for the Nedelec
+                                     * Constructor for the Nédélec
                                      * element of degree @p p.
                                      */
-    FE_Nedelec (const unsigned int p);
-    
+      FE_Nedelec (const unsigned int p);
+
                                     /**
                                      * Return a string that uniquely
                                      * identifies a finite
@@ -204,254 +86,99 @@ class FE_Nedelec : public FiniteElement<dim,spacedim>
                                      */
     virtual std::string get_name () const;
 
-                                    /**
-                                     * Return the value of the
-                                     * @p componentth vector
-                                     * component of the @p ith shape
-                                     * function at the point
-                                     * @p p. See the
-                                     * FiniteElement base
-                                     * class for more information
-                                     * about the semantics of this
-                                     * function.
-                                     */
-    virtual double shape_value_component (const unsigned int i,
-                                         const Point<dim> &p,
-                                         const unsigned int component) const;
 
                                     /**
-                                     * Return the gradient of the
-                                     * @p componentth vector
-                                     * component of the @p ith shape
-                                     * function at the point
-                                     * @p p. See the
-                                     * FiniteElement base
-                                     * class for more information
-                                     * about the semantics of this
-                                     * function.
+                                     * Check whether a shape function
+                                     * may be non-zero on a face.
                                      */
-    virtual Tensor<1,dim> shape_grad_component (const unsigned int i,
-                                               const Point<dim> &p,
-                                               const unsigned int component) const;
+    virtual bool has_support_on_face (const unsigned int shape_index, const unsigned int face_index) const;
 
                                     /**
-                                     * Return the second derivative
-                                     * of the @p componentth vector
-                                     * component of the @p ith shape
-                                     * function at the point
-                                     * @p p. See the
-                                     * FiniteElement base
-                                     * class for more information
-                                     * about the semantics of this
-                                     * function.
+                                     * Return whether this element implements its
+                                     * hanging node constraints in the new way, which
+                                     * has to be used to make elements "hp compatible".
+                                     *
+                                     * For the <tt>FE_Nedelec</tt> class the result is
+                                     * always true (independent of the degree of the
+                                     * element), as it implements the complete set of
+                                     * functions necessary for hp capability.
                                      */
-    virtual Tensor<2,dim> shape_grad_grad_component (const unsigned int i,
-                                                    const Point<dim> &p,
-                                                    const unsigned int component) const;
+    virtual bool hp_constraints_are_implemented () const;
 
                                     /**
-                                     * Return the polynomial degree
-                                     * of this finite element,
-                                     * i.e. the value passed to the
-                                     * constructor.
+                                     * If, on a vertex, several finite elements are
+                                     * active, the hp code first assigns the degrees
+                                     * of freedom of each of these FEs different global
+                                     * indices. It then calls this function to find
+                                     * out which of them should get identical values,
+                                     * and consequently can receive the same global DoF
+                                     * index. This function therefore returns a list
+                                     * of identities between DoFs of the present finite
+                                     * element object with the DoFs of fe_other, which
+                                     * is a reference to a finite element object representing
+                                     * one of the other finite elements active on this
+                                     * particular vertex. The function computes which
+                                     * of the degrees of freedom of the two finite
+                                     * element objects are equivalent, and returns a
+                                     * list of pairs of global dof indices in identities.
+                                     * The first index of each pair denotes one of the
+                                     * vertex dofs of the present element, whereas the
+                                     * second is the corresponding index of the other
+                                     * finite element.
                                      */
-    unsigned int get_degree () const;
-    
-                                    /**
-                                     * Number of base elements in a
-                                     * mixed discretization. Here,
-                                     * this is of course equal to
-                                     * one.
-                                     */
-    virtual unsigned int n_base_elements () const;
-    
-                                    /**
-                                     * Access to base element
-                                     * objects. Since this element is
-                                     * atomic, <tt>base_element(0)</tt> is
-                                     * @p this, and all other
-                                     * indices throw an error.
-                                     */
-    virtual const FiniteElement<dim,spacedim> &
-    base_element (const unsigned int index) const;
+    virtual std::vector<std::pair<unsigned int, unsigned int> > hp_vertex_dof_identities (const FiniteElement<dim>& fe_other) const;
 
-                                     /**
-                                      * Multiplicity of base element
-                                      * @p index. Since this is an
-                                      * atomic element,
-                                      * <tt>element_multiplicity(0)</tt>
-                                      * returns one, and all other
-                                      * indices will throw an error.
-                                      */
-    virtual unsigned int element_multiplicity (const unsigned int index) const;
-    
                                     /**
-                                     * This function returns
-                                     * @p true, if the shape
-                                     * function @p shape_index has
-                                     * non-zero values on the face
-                                     * @p face_index. For the lowest
-                                     * order Nedelec elements, this
-                                     * is actually the case for the
-                                     * one on which the shape
-                                     * function is defined and all
-                                     * neighboring ones.
-                                     *
-                                     * Implementation of the
-                                     * interface in
-                                     * FiniteElement
+                                     * Same as hp_vertex_dof_indices(), except that
+                                     * the function treats degrees of freedom on lines.
                                      */
-    virtual bool has_support_on_face (const unsigned int shape_index,
-                                     const unsigned int face_index) const;
+    virtual std::vector<std::pair<unsigned int, unsigned int> > hp_line_dof_identities (const FiniteElement<dim>& fe_other) const;
 
                                     /**
-                                     * Determine an estimate for the
-                                     * memory consumption (in bytes)
-                                     * of this object.
-                                     *
-                                     * This function is made virtual,
-                                     * since finite element objects
-                                     * are usually accessed through
-                                     * pointers to their base class,
-                                     * rather than the class itself.
+                                     * Same as hp_vertex_dof_indices(), except that
+                                     * the function treats degrees of freedom on lines.
                                      */
-    virtual unsigned int memory_consumption () const;
-
+    virtual std::vector<std::pair<unsigned int, unsigned int> > hp_quad_dof_identities (const FiniteElement<dim>& fe_other) const;
 
                                     /**
-                                     * Declare a nested class which
-                                     * will hold static definitions of
-                                     * various matrices such as
-                                     * constraint and embedding
-                                     * matrices. The definition of
-                                     * the various static fields are
-                                     * in the files <tt>fe_nedelec_[23]d.cc</tt>
-                                     * in the source directory.
+                                     * Return the matrix interpolating from a face of one
+                                     * element to the face of the neighboring element. The
+                                     * size of the matrix is then <tt>source.dofs_per_face</tt>
+                                     * times <tt>this->dofs_per_face</tt>.
+                                     *
+                                     * Derived elements will have to implement this function.
+                                     * They may only provide interpolation matrices for certain
+                                     * source finite elements, for example those from the same
+                                     * family. If they don't implement interpolation from a given
+                                     * element, then they must throw an exception of type
+                                     * <tt>FiniteElement<dim>::ExcInterpolationNotImplemented</tt>.
                                      */
-    struct Matrices
-    {
-                                        /**
-                                         * Embedding matrices. For
-                                         * each element type (the
-                                         * first index) there are as
-                                         * many embedding matrices as
-                                         * there are children per
-                                         * cell. The first index
-                                         * starts with linear
-                                         * elements and goes up in
-                                         * polynomial degree. The
-                                         * array may grow in the
-                                         * future with the number of
-                                         * elements for which these
-                                         * matrices have been
-                                         * computed. If for some
-                                         * element, the matrices have
-                                         * not been computed then you
-                                         * may use the element
-                                         * nevertheless but can not
-                                         * access the respective
-                                         * fields.
-                                         */
-       static const double * const
-       embedding[][GeometryInfo<dim>::max_children_per_cell];
+    virtual void get_face_interpolation_matrix (const FiniteElement<dim>& source, FullMatrix<double>& matrix) const;
 
-                                        /**
-                                         * Number of elements (first
-                                         * index) the above field
-                                         * has. Equals the highest
-                                         * polynomial degree for
-                                         * which the embedding
-                                         * matrices have been
-                                         * computed.
-                                         */
-       static const unsigned int n_embedding_matrices;
-
-                                        /**
-                                         * As the
-                                         * @p embedding_matrices
-                                         * field, but for the
-                                         * interface constraints. One
-                                         * for each element for which
-                                         * it has been computed.
-                                         */
-       static const double * const constraint_matrices[];
-
-                                        /**
-                                         * Like
-                                         * @p n_embedding_matrices,
-                                         * but for the number of
-                                         * interface constraint
-                                         * matrices.
-                                         */
-       static const unsigned int n_constraint_matrices;
-    };
-  protected:    
                                     /**
-                                     * @p clone function instead of
-                                     * a copy constructor.
+                                     * Return the matrix interpolating from a face of one element
+                                     * to the subface of the neighboring element. The size of
+                                     * the matrix is then <tt>source.dofs_per_face</tt> times
+                                     * <tt>this->dofs_per_face</tt>.
                                      *
-                                     * This function is needed by the
-                                     * constructors of @p FESystem.
-                                     */
-    virtual FiniteElement<dim,spacedim> * clone() const;
-  
-                                    /**
-                                     * Prepare internal data
-                                     * structures and fill in values
-                                     * independent of the cell.
+                                     * Derived elements will have to implement this function.
+                                     * They may only provide interpolation matrices for certain
+                                     * source finite elements, for example those from the same
+                                     * family. If they don't implement interpolation from a given
+                                     * element, then they must throw an exception of type
+                                     * <tt>ExcInterpolationNotImplemented</tt>.
                                      */
-    virtual
-    typename Mapping<dim,spacedim>::InternalDataBase *
-    get_data (const UpdateFlags,
-             const Mapping<dim,spacedim>& mapping,
-             const Quadrature<dim>& quadrature) const ;
+    virtual void get_subface_interpolation_matrix (const FiniteElement<dim>& source, const unsigned int subface, FullMatrix<double>& matrix) const;
 
-                                    /**
-                                     * Implementation of the same
-                                     * function in
-                                     * FiniteElement.
-                                     */
-    virtual void
-    fill_fe_values (const Mapping<dim,spacedim>                      &mapping,
-                   const typename Triangulation<dim,spacedim>::cell_iterator &cell,
-                   const Quadrature<dim>                            &quadrature,
-                   typename Mapping<dim,spacedim>::InternalDataBase &mapping_internal,
-                   typename Mapping<dim,spacedim>::InternalDataBase &fe_internal,
-                   FEValuesData<dim,spacedim>                       &data,
-                   CellSimilarity::Similarity                  &cell_similarity) const;
-    
-                                    /**
-                                     * Implementation of the same
-                                     * function in
-                                     * FiniteElement.
-                                     */
-    virtual void
-    fill_fe_face_values (const Mapping<dim,spacedim> &mapping,
-                        const typename Triangulation<dim,spacedim>::cell_iterator &cell,
-                        const unsigned int                    face_no,
-                        const Quadrature<dim-1>                &quadrature,
-                        typename Mapping<dim,spacedim>::InternalDataBase      &mapping_internal,
-                        typename Mapping<dim,spacedim>::InternalDataBase      &fe_internal,
-                        FEValuesData<dim,spacedim>& data) const ;
-    
-                                    /**
-                                     * Implementation of the same
-                                     * function in
-                                     * FiniteElement.
-                                     */
-    virtual void
-    fill_fe_subface_values (const Mapping<dim,spacedim> &mapping,
-                           const typename Triangulation<dim,spacedim>::cell_iterator &cell,
-                           const unsigned int                    face_no,
-                           const unsigned int                    sub_no,
-                           const Quadrature<dim-1>                &quadrature,
-                           typename Mapping<dim,spacedim>::InternalDataBase      &mapping_internal,
-                           typename Mapping<dim,spacedim>::InternalDataBase      &fe_internal,
-                           FEValuesData<dim,spacedim>& data) const ;
+    virtual void interpolate (std::vector<double>& local_dofs, const std::vector<double>& values) const;
 
-  private:
+    virtual void interpolate (std::vector<double>& local_dofs, const std::vector<Vector<double> >& values, unsigned int offset = 0) const;
+    virtual void interpolate (std::vector<double>& local_dofs, const VectorSlice<const std::vector<std::vector<double> > >& values) const;
+    virtual unsigned int memory_consumption () const;
+    virtual FiniteElement<dim> * clone() const;
     
-                                    /**
+  private:
+                                /**
                                      * Only for internal use. Its
                                      * full name is
                                      * @p get_dofs_per_object_vector
@@ -461,91 +188,32 @@ class FE_Nedelec : public FiniteElement<dim,spacedim>
                                      * be passed to the constructor of
                                      * @p FiniteElementData.
                                      */
-    static std::vector<unsigned int> get_dpo_vector(const unsigned int degree);
-
+    static std::vector<unsigned int> get_dpo_vector (const unsigned int degree);
 
                                     /**
-                                     * Initialize the hanging node
-                                     * constraints matrices. Called
+                                     * Initialize the @p
+                                     * generalized_support_points
+                                     * field of the FiniteElement
+                                     * class and fill the tables with
+                                     * interpolation weights
+                                     * (#boundary_weights and
+                                     * #interior_weights). Called
                                      * from the constructor.
                                      */
-    void initialize_constraints ();
-
-                                    /**
-                                     * Initialize the embedding
-                                     * matrices. Called from the
-                                     * constructor.
-                                     */
-    void initialize_embedding ();
+    void initialize_support_points (const unsigned int degree);
 
                                     /**
-                                     * Initialize the restriction
-                                     * matrices. Called from the
-                                     * constructor.
+                                     * Initialize the interpolation
+                                     * from functions on refined mesh
+                                     * cells onto the father
+                                     * cell. According to the
+                                     * philosophy of the
+                                     * Nédélec element, this
+                                     * restriction operator preserves
+                                     * the curl of a function
+                                     * weakly.
                                      */
     void initialize_restriction ();
-    
-                                    /**
-                                     * Initialize the
-                                     * @p unit_support_points field
-                                     * of the FiniteElement
-                                     * class. Called from the
-                                     * constructor.
-                                     */
-    void initialize_unit_support_points ();
-
-                                    /**
-                                     * Initialize the
-                                     * @p unit_face_support_points field
-                                     * of the FiniteElement
-                                     * class. Called from the
-                                     * constructor.
-                                     */
-    void initialize_unit_face_support_points ();
-    
-                                    /**
-                                     * Given a set of flags indicating
-                                     * what quantities are requested
-                                     * from a @p FEValues object,
-                                     * return which of these can be
-                                     * precomputed once and for
-                                     * all. Often, the values of
-                                     * shape function at quadrature
-                                     * points can be precomputed, for
-                                     * example, in which case the
-                                     * return value of this function
-                                     * would be the logical and of
-                                     * the input @p flags and
-                                     * @p update_values.
-                                     *
-                                     * For the present kind of finite
-                                     * element, this is exactly the
-                                     * case.
-                                     */
-    virtual UpdateFlags update_once (const UpdateFlags flags) const;
-  
-                                    /**
-                                     * This is the opposite to the
-                                     * above function: given a set of
-                                     * flags indicating what we want
-                                     * to know, return which of these
-                                     * need to be computed each time
-                                     * we visit a new cell.
-                                     *
-                                     * If for the computation of one
-                                     * quantity something else is
-                                     * also required (for example, we
-                                     * often need the covariant
-                                     * transformation when gradients
-                                     * need to be computed), include
-                                     * this in the result as well.
-                                     */
-    virtual UpdateFlags update_each (const UpdateFlags flags) const;
-    
-                                    /**
-                                     * Degree of the polynomials.
-                                     */  
-    const unsigned int degree;
 
                                     /**
                                      * Fields of cell-independent data.
@@ -555,7 +223,7 @@ class FE_Nedelec : public FiniteElement<dim,spacedim>
                                      * see the documentation of the
                                      * base class.
                                      */
-    class InternalData : public FiniteElement<dim,spacedim>::InternalDataBase
+    class InternalData : public FiniteElement<dim>::InternalDataBase
     {
       public:
                                         /**
@@ -581,7 +249,7 @@ class FE_Nedelec : public FiniteElement<dim,spacedim>
                                          * multiplication with the
                                          * Jacobian of the mapping.
                                          */
-       std::vector<std::vector<Tensor<1,dim> > > shape_values;
+       std::vector<std::vector<Tensor<1, dim> > > shape_values;
 
                                         /**
                                          * Array with shape function
@@ -601,127 +269,39 @@ class FE_Nedelec : public FiniteElement<dim,spacedim>
                                          * multiplication) when
                                          * visiting an actual cell.
                                          */
-       std::vector<std::vector<Tensor<2,dim> > > shape_gradients;
+       std::vector<std::vector<Tensor<2, dim> > > shape_gradients;
     };
+
+    const unsigned int deg;
+                                    /**
+                                     * These are the factors
+                                     * multiplied to a function in
+                                     * the
+                                     * #generalized_face_support_points
+                                     * when computing the
+                                     * integration.
+                                     */
+    Table<2, double> boundary_weights;
     
                                     /**
                                      * Allow access from other
                                      * dimensions.
                                      */
-    template <int , int> friend class FE_Nedelec;
+    template <int dim1> friend class FE_Nedelec;
 };
 
-/*@}*/
-
-#ifndef DOXYGEN
-
-
 /* -------------- declaration of explicit specializations ------------- */
 
-template <>
-void FE_Nedelec<1,1>::initialize_unit_face_support_points ();
-
-template <>
-double
-FE_Nedelec<1,1>::shape_value_component (const unsigned int ,
-                                      const Point<1>    &,
-                                      const unsigned int ) const;
-
-template <>
-double
-FE_Nedelec<2,2>::shape_value_component (const unsigned int ,
-                                      const Point<2>    &,
-                                      const unsigned int ) const;
-
-template <>
-double
-FE_Nedelec<3,3>::shape_value_component (const unsigned int ,
-                                      const Point<3>    &,
-                                      const unsigned int ) const;
-
-template <>
-Tensor<1,1>
-FE_Nedelec<1,1>::shape_grad_component (const unsigned int ,
-                                     const Point<1>    &,
-                                     const unsigned int ) const;
-
-template <>
-Tensor<1,2>
-FE_Nedelec<2,2>::shape_grad_component (const unsigned int ,
-                                     const Point<2>    &,
-                                     const unsigned int ) const;
-
-template <>
-Tensor<1,3>
-FE_Nedelec<3,3>::shape_grad_component (const unsigned int ,
-                                     const Point<3>    &,
-                                     const unsigned int ) const;
-
-template <>
-Tensor<2,1>
-FE_Nedelec<1,1>::shape_grad_grad_component (const unsigned int ,
-                                          const Point<1>    &,
-                                          const unsigned int ) const;
-
-template <>
-Tensor<2,2>
-FE_Nedelec<2,2>::shape_grad_grad_component (const unsigned int ,
-                                          const Point<2>    &,
-                                          const unsigned int ) const;
-
-template <>
-Tensor<2,3>
-FE_Nedelec<3,3>::shape_grad_grad_component (const unsigned int ,
-                                          const Point<3>    &,
-                                          const unsigned int ) const;
-
-
-
-// declaration of explicit specializations of member variables, if the
-// compiler allows us to do that (the standard says we must)
-#ifndef DEAL_II_MEMBER_VAR_SPECIALIZATION_BUG
-template <> 
-const double * const 
-FE_Nedelec<1,1>::Matrices::embedding[][GeometryInfo<1>::max_children_per_cell];
-
-template <>
-const unsigned int FE_Nedelec<1,1>::Matrices::n_embedding_matrices;
-
-template <>
-const double * const FE_Nedelec<1,1>::Matrices::constraint_matrices[];
-
-template <>
-const unsigned int FE_Nedelec<1,1>::Matrices::n_constraint_matrices;
-
-template <> 
-const double * const 
-FE_Nedelec<2,2>::Matrices::embedding[][GeometryInfo<2>::max_children_per_cell];
-
-template <>
-const unsigned int FE_Nedelec<2,2>::Matrices::n_embedding_matrices;
-
-template <>
-const double * const FE_Nedelec<2,2>::Matrices::constraint_matrices[];
-
-template <>
-const unsigned int FE_Nedelec<2,2>::Matrices::n_constraint_matrices;
-
-template <> 
-const double * const 
-FE_Nedelec<3,3>::Matrices::embedding[][GeometryInfo<3>::max_children_per_cell];
-
-template <>
-const unsigned int FE_Nedelec<3,3>::Matrices::n_embedding_matrices;
+#ifndef DOXYGEN
 
 template <>
-const double * const FE_Nedelec<3,3>::Matrices::constraint_matrices[];
-
+std::vector<unsigned int> FE_Nedelec<1>::get_dpo_vector (const unsigned int);
 template <>
-const unsigned int FE_Nedelec<3,3>::Matrices::n_constraint_matrices;
+void
+FE_Nedelec<1>::initialize_restriction();
 
-#endif
 #endif // DOXYGEN
 
 DEAL_II_NAMESPACE_CLOSE
 
-#endif
+#endif
\ No newline at end of file
index cd958fbb2332b0d67f5c9edbc8c8a23d725f80c3..363b8d00e7ad25fb3bd1b6a84f35fcf0863f5022 100644 (file)
@@ -1,88 +1,96 @@
-//---------------------------------------------------------------------------
-//    $Id$
-//    Version: $Name$
-//
-//    Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by the deal.II authors
-//
-//    This file is subject to QPL and may not be  distributed
-//    without copyright and license information. Please refer
-//    to the file deal.II/doc/license.html for the  text  and
-//    further information on this license.
-//
-//---------------------------------------------------------------------------
-
+#include <base/logstream.h>
+#include <base/utilities.h>
 #include <base/quadrature.h>
+#include <base/quadrature_lib.h>
 #include <base/qprojector.h>
-#include <base/table.h>
 #include <grid/tria.h>
 #include <grid/tria_iterator.h>
 #include <dofs/dof_accessor.h>
-#include <fe/fe.h>
 #include <fe/mapping.h>
 #include <fe/fe_nedelec.h>
+#include <fe/fe_nothing.h>
 #include <fe/fe_values.h>
-
+#include <fe/fe_tools.h>
+#include <lac/full_matrix.h>
+#include <lac/vector.h>
 #include <sstream>
+#include <iostream>
+
+//TODO: implement the adjust_quad_dof_index_for_face_orientation_table and
+//adjust_line_dof_index_for_line_orientation_table fields, and write tests
+//similar to bits/face_orientation_and_fe_q_*
 
-//TODO: implement the adjust_line_dof_index_for_line_orientation_table field,
-//and write a test similar to bits/face_orientation_and_fe_q_02
 
 DEAL_II_NAMESPACE_OPEN
 
 
-//TODO: Remove doubled member variable 'degree'
-template <int dim, int spacedim>
-FE_Nedelec<dim,spacedim>::FE_Nedelec (const unsigned int degree)
-               :
-               FiniteElement<dim,spacedim> (
-                 FiniteElementData<dim>(get_dpo_vector(degree), dim,
-                                        degree+1, FiniteElementData<dim>::Hcurl, 1),
-                                   std::vector<bool> (
-                                     FiniteElementData<dim>(get_dpo_vector(degree), dim,
-                                                            degree+1).dofs_per_cell,false),
-                                   std::vector<std::vector<bool> >(
-                                     FiniteElementData<dim>(get_dpo_vector(degree), dim,
-                                                            degree+1).dofs_per_cell,
-                                     std::vector<bool>(dim,true))),
-               degree(degree)
+template <int dim>
+FE_Nedelec<dim>::FE_Nedelec (const unsigned int p) :
+FE_PolyTensor<PolynomialsNedelec<dim>, dim>
+(p,
+ FiniteElementData<dim> (get_dpo_vector (p), dim, p + 1,
+                         FiniteElementData<dim>::Hcurl, 1),
+ std::vector<bool> (PolynomialsNedelec<dim>::compute_n_pols (p), true),
+ std::vector<std::vector<bool> >
+ (PolynomialsNedelec<dim>::compute_n_pols (p),
+  std::vector<bool> (dim, true))),
+deg (p)
 {
   Assert (dim >= 2, ExcImpossibleInDim(dim));
+
+  const unsigned int n_dofs = this->dofs_per_cell;
+
+  this->mapping_type = mapping_nedelec;
+                                  // First, initialize the
+                                  // generalized support points and
+                                  // quadrature weights, since they
+                                  // are required for interpolation.
+  initialize_support_points (p);
+  this->inverse_node_matrix.reinit (n_dofs, n_dofs);
+  this->inverse_node_matrix.fill
+    (FullMatrix<double> (IdentityMatrix (n_dofs)));
+                                  // From now on, the shape functions
+                                  // will be the correct ones, not
+                                  // the raw shape functions anymore.
   
-                                  // copy constraint and embedding
-                                  // matrices if they are
-                                  // defined. otherwise leave them at
-                                  // invalid size
-  initialize_constraints ();
-  initialize_embedding ();
+                                  // Reinit the vectors of
+                                  // restriction and prolongation
+                                  // matrices to the right sizes.
+                                  // Restriction only for isotropic
+                                  // refinement
+  this->reinit_restriction_and_prolongation_matrices ();
+                                  // Fill prolongation matrices with embedding operators
+  FETools::compute_embedding_matrices (*this, this->prolongation);
   initialize_restriction ();
 
-                                  // finally fill in support points
-                                  // on cell and face
-  initialize_unit_support_points ();
-  initialize_unit_face_support_points ();
-
-                                  // finite element classes need to
-                                  // initialize the
-                                  // adjust_quad_dof_index... table. however,
-                                  // for the current element, there are no
-                                  // dofs on quads in 3d (i.e. in the
-                                  // interior of a face), so there is nothing
-                                  // to do
-  if (dim == 3)
-    {
-      Assert (this->dofs_per_quad == 0,
-             ExcInternalError());
-      Assert (this->adjust_quad_dof_index_for_face_orientation_table.size(0)==
-             this->dofs_per_quad,
-             ExcInternalError());
-    }
+  FullMatrix<double> face_embeddings[GeometryInfo<dim>::max_children_per_face];
+
+  for (unsigned int i = 0; i < GeometryInfo<dim>::max_children_per_face; ++i)
+     face_embeddings[i].reinit (this->dofs_per_face, this->dofs_per_face);
+
+  FETools::compute_face_embedding_matrices<dim,double>
+    (*this, face_embeddings, 0, 0);
+  this->interface_constraints.reinit ((1 << (dim - 1)) * this->dofs_per_face,
+                                      this->dofs_per_face);
+
+  unsigned int target_row = 0;
+
+  for (unsigned int i = 0; i < GeometryInfo<dim>::max_children_per_face; ++i)
+    for (unsigned int j = 0; j < face_embeddings[i].m (); ++j)
+      {
+        for (unsigned int k = 0; k < face_embeddings[i].n (); ++k)
+          this->interface_constraints (target_row, k)
+            = face_embeddings[i] (j, k);
+
+        ++target_row;
+      }
 }
 
 
 
-template <int dim, int spacedim>
+template <int dim>
 std::string
-FE_Nedelec<dim,spacedim>::get_name () const
+FE_Nedelec<dim>::get_name () const
 {
                                   // note that the
                                   // FETools::get_fe_from_name
@@ -92,1430 +100,5866 @@ FE_Nedelec<dim,spacedim>::get_name () const
                                   // have to be kept in synch
 
   std::ostringstream namebuf;  
-  namebuf << "FE_Nedelec<" << dim << ">(" << degree << ")";
+  namebuf << "FE_Nedelec<" << dim << ">(" << deg << ")";
 
   return namebuf.str();
 }
 
 
-
-template <int dim, int spacedim>
-FiniteElement<dim,spacedim> *
-FE_Nedelec<dim,spacedim>::clone() const
+template <int dim>
+FiniteElement<dim>
+*FE_Nedelec<dim>::clone () const
 {
-  return new FE_Nedelec<dim,spacedim>(*this);
+  return new FE_Nedelec<dim(*this);
 }
 
+//---------------------------------------------------------------------------
+// Auxiliary and internal functions
+//---------------------------------------------------------------------------
+
 
 #if deal_II_dimension == 1
 
-template <>
-double
-FE_Nedelec<1>::shape_value_component (const unsigned int ,
-                                    const Point<1>    &,
-                                    const unsigned int ) const
+                   // Set the generalized support
+                   // points and precompute the 
+                   // parts of the projection-based
+                   // interpolation, which does
+                   // not depend on the interpolated
+                   // function.
+template <int dim>
+void
+FE_Nedelec<dim>::initialize_support_points (const unsigned int degree)
 {
-  Assert (false, ExcNotImplemented());
-  return 0.;
+  Assert (false, ExcNotImplemented ());
 }
 
-#endif
+#else
 
-#if deal_II_dimension == 2
-
-template <>
-double
-FE_Nedelec<2>::shape_value_component (const unsigned int i,
-                                     const Point<2>    &p,
-                                     const unsigned int component) const
+// Version for 2d and higher. See above for 1d version
+template <int dim>
+void
+FE_Nedelec<dim>::initialize_support_points (const unsigned int degree)
 {
-  const unsigned int dim = 2;
-  
-  Assert (i<this->dofs_per_cell, ExcIndexRange(i,0,this->dofs_per_cell));
-  Assert (component < dim, ExcIndexRange (component, 0, dim));
-  
-  switch (degree)
-    {
-                                      // first order Nedelec elements
-      case 1:
-      {
-       switch (i)
-         {
-                                                  // (0, 1-x)
-           case 0: return (component == 0 ? 0 : 1-p(0));
-                                                  // (0,x)
-           case 1: return (component == 0 ? 0 : p(0));
-                                                  // (1-y, 0)
-           case 2: return (component == 0 ? 1-p(1) : 0);
-                                                  // (y, 0)
-           case 3: return (component == 0 ? p(1) : 0);
-                        
-                                                  // there are only
-                                                  // four shape
-                                                  // functions!?
-           default:
-                 Assert (false, ExcInternalError());
-                 return 0;
-         };
-      };
-
-                                       // no other degrees
-                                       // implemented
-      default:
-           Assert (false, ExcNotImplemented());
-    };
-  
-  return 0;
-}
+                      // Create polynomial basis.
+  const std::vector<Polynomials::Polynomial<double> >& lobatto_polynomials
+    = Polynomials::Lobatto::generate_complete_basis (degree + 1);
+  std::vector<Polynomials::Polynomial<double> >
+    lobatto_polynomials_grad (degree + 1);
 
-#endif
-
-#if deal_II_dimension == 3
+  for (unsigned int i = 0; i < lobatto_polynomials_grad.size (); ++i)
+    lobatto_polynomials_grad[i] = lobatto_polynomials[i + 1].derivative ();
 
-template <>
-double
-FE_Nedelec<3>::shape_value_component (const unsigned int i,
-                                     const Point<3>    &p,
-                                     const unsigned int component) const
-{
-  const unsigned int dim = 3;
-  
-  Assert (i<this->dofs_per_cell, ExcIndexRange(i,0,this->dofs_per_cell));
-  Assert (component < dim, ExcIndexRange (component, 0, dim));
-  
-  switch (degree)
+  switch (dim)
     {
-                                      // first order Nedelec
-                                      // elements
-      case 1:
-      {
-                                        // note that the degrees of
-                                        // freedom on opposite faces
-                                        // have a common vector
-                                        // direction, so simplify that
-                                        // a little. these directions
-                                        // are:
-                                        //
-                                        // for lines 2, 3, 6, 7:
-                                        //    (1,0,0)
-                                        // for lines 0, 1, 4, 5:
-                                        //    (0,1,0)
-                                        // for lines 8, 9, 10, 11:
-                                        //    (0,0,1)
-                                        //
-                                        // thus, sort out all those
-                                        // cases where the component
-                                        // is zero anyway, and only
-                                        // otherwise compute the
-                                        // spatially dependent part
-                                        // which is then also the
-                                        // return value
-       if (((i<8) && (((i%4>=2) && (component!=0)) ||
-                      ((i%4<2) && (component!=1)))) ||
-           ((i>=8) && (component != 2)))
-         return 0;
-
-                                              // now we know that the
-                                              // only non-zero
-                                              // component is
-                                              // requested:
-       const double x = p(0),
-                    y = p(1),
-                    z = p(2);
-       switch (i)
-         {
-           case  0: return (1-x)*(1-z);
-           case  1: return     x*(1-z);
-           case  2: return (1-y)*(1-z);
-           case  3: return     y*(1-z);
-
-           case  4: return (1-x)*z;
-           case  5: return     x*z;
-           case  6: return (1-y)*z;
-           case  7: return     y*z;
-
-           case  8: return (1-x)*(1-y);
-           case  9: return     x*(1-y);
-           case 10: return (1-x)*y;
-           case 11: return     x*y;
-                       
-           default:
-                 Assert (false, ExcInternalError());
-                 return 0;
-         };
-      };
-
-                                       // no other degrees
-                                       // implemented
+      case 2:
+        {
+                      // Initialize quadratures to obtain
+                      // quadrature points later on.
+          const QGauss<dim - 1> reference_edge_quadrature (degree + 1);
+          const unsigned int&
+            n_edge_points = reference_edge_quadrature.size ();
+          const unsigned int n_boundary_points
+            = GeometryInfo<dim>::lines_per_cell * n_edge_points;
+          const Quadrature<dim>& edge_quadrature
+            = QProjector<dim>::project_to_all_faces (reference_edge_quadrature);
+
+          this->generalized_face_support_points.resize (n_edge_points);
+
+                   // Create face support points.
+          for (unsigned int q_point = 0; q_point < n_edge_points; ++q_point)
+            this->generalized_face_support_points[q_point]
+              = reference_edge_quadrature.point (q_point);
+
+          if (degree > 0)
+            {
+                   // If the polynomial degree is positive
+                   // we have support points on the faces
+                   // and in the interior of a cell.
+              const QGauss<dim> quadrature (degree + 1);
+              const unsigned int& n_interior_points = quadrature.size ();
+
+              this->generalized_support_points.resize
+                (n_boundary_points + n_interior_points);
+              boundary_weights.reinit (n_edge_points, degree);
+
+              for (unsigned int q_point = 0; q_point < n_edge_points;
+                   ++q_point)
+                {
+                  for (unsigned int line = 0;
+                       line < GeometryInfo<dim>::lines_per_cell; ++line)
+                    this->generalized_support_points[line * n_edge_points
+                                                     + q_point]
+                      = edge_quadrature.point
+                        (QProjector<dim>::DataSetDescriptor::face
+                         (line, true, false, false, n_edge_points) + q_point);
+
+                  for (unsigned int i = 0; i < degree; ++i)
+                    boundary_weights (q_point, i)
+                      = reference_edge_quadrature.weight (q_point)
+                        * lobatto_polynomials_grad[i + 1].value
+                          (this->generalized_face_support_points[q_point] (0));
+                }
+
+              for (unsigned int q_point = 0; q_point < n_interior_points;
+                   ++q_point)
+                this->generalized_support_points[q_point + n_boundary_points]
+                  = quadrature.point (q_point);
+            }
+          
+          else
+            {
+                   // In this case we only need support points
+                   // on the faces of a cell.
+              const Quadrature<dim>& edge_quadrature
+                = QProjector<dim>::project_to_all_faces
+                  (reference_edge_quadrature);
+              
+              this->generalized_support_points.resize (n_boundary_points);
+
+              for (unsigned int line = 0;
+                   line < GeometryInfo<dim>::lines_per_cell; ++line)
+                for (unsigned int q_point = 0; q_point < n_edge_points;
+                     ++q_point)
+                  this->generalized_support_points[line * n_edge_points
+                                                   + q_point]
+                    = edge_quadrature.point
+                      (QProjector<dim>::DataSetDescriptor::face
+                       (line, true, false, false, n_edge_points) + q_point);
+            }
+
+          break;
+        }
+
+      case 3:
+        {
+                      // Initialize quadratures to obtain
+                      // quadrature points later on.
+          const QGauss<dim - 2> reference_edge_quadrature (degree + 1);
+          const unsigned int& n_edge_points = reference_edge_quadrature.size ();
+          const Quadrature<dim - 1>& edge_quadrature
+            = QProjector<dim - 1>::project_to_all_faces
+              (reference_edge_quadrature);
+
+          if (degree > 0)
+            {
+                   // If the polynomial degree is positive
+                   // we have support points on the edges,
+                   // faces and in the interior of a cell.
+              const QGauss<dim - 1> reference_face_quadrature (degree + 1);
+              const unsigned int& n_face_points
+                = reference_face_quadrature.size ();
+              const unsigned int n_boundary_points
+                = GeometryInfo<dim>::lines_per_cell * n_edge_points
+                  + GeometryInfo<dim>::faces_per_cell * n_face_points;
+              const QGauss<dim> quadrature (degree + 1);
+              const unsigned int& n_interior_points = quadrature.size ();
+
+              boundary_weights.reinit (n_edge_points + n_face_points,
+                                       2 * (degree + 1) * degree);
+              this->generalized_face_support_points.resize
+                (4 * n_edge_points + n_face_points);
+              this->generalized_support_points.resize
+                (n_boundary_points + n_interior_points);
+
+                   // Create support points on edges.
+              for (unsigned int q_point = 0; q_point < n_edge_points; ++q_point)
+                {
+                  for (unsigned int line = 0;
+                       line < GeometryInfo<dim - 1>::lines_per_cell; ++line)
+                    this->generalized_face_support_points[line * n_edge_points
+                                                          + q_point]
+                      = edge_quadrature.point
+                        (QProjector<dim - 1>::DataSetDescriptor::face
+                         (line, true, false, false, n_edge_points) + q_point);
+
+                  for (unsigned int i = 0; i < 2; ++i)
+                    for (unsigned int j = 0; j < 2; ++j)
+                      {
+                        this->generalized_support_points
+                          [q_point + (i + 4 * j) * n_edge_points]
+                          = Point<dim>
+                            (i, reference_edge_quadrature.point (q_point) (0),
+                             j);
+                        this->generalized_support_points
+                          [q_point + (i + 4 * j + 2) * n_edge_points]
+                          = Point<dim>
+                            (reference_edge_quadrature.point (q_point) (0),
+                             i, j);
+                        this->generalized_support_points
+                          [q_point + (i + 2 * (j + 4)) * n_edge_points]
+                          = Point<dim>
+                            (i, j,
+                             reference_edge_quadrature.point (q_point) (0));
+                      }
+
+                  for (unsigned int i = 0; i < degree; ++i)
+                    boundary_weights (q_point, i)
+                      = reference_edge_quadrature.weight (q_point)
+                        * lobatto_polynomials_grad[i + 1].value
+                          (this->generalized_face_support_points[q_point] (1));
+                }
+
+                   // Create support points on faces.
+              for (unsigned int q_point = 0; q_point < n_face_points;
+                   ++q_point)
+                {
+                  this->generalized_face_support_points[q_point
+                                                        + 4 * n_edge_points]
+                    = reference_face_quadrature.point (q_point);
+
+                  for (unsigned int i = 0; i <= degree; ++i)
+                    for (unsigned int j = 0; j < degree; ++j)
+                      {
+                        boundary_weights (q_point + n_edge_points,
+                                          2 * (i * degree + j))
+                          = reference_face_quadrature.weight (q_point)
+                            * lobatto_polynomials_grad[i].value
+                              (this->generalized_face_support_points
+                               [q_point + 4 * n_edge_points] (0))
+                            * lobatto_polynomials[j + 2].value
+                              (this->generalized_face_support_points
+                               [q_point + 4 * n_edge_points] (1));
+                        boundary_weights (q_point + n_edge_points,
+                                          2 * (i * degree + j) + 1)
+                          = reference_face_quadrature.weight (q_point)
+                            * lobatto_polynomials_grad[i].value
+                              (this->generalized_face_support_points
+                               [q_point + 4 * n_edge_points] (1))
+                            * lobatto_polynomials[j + 2].value
+                              (this->generalized_face_support_points
+                               [q_point + 4 * n_edge_points] (0));
+                      }
+                }
+
+              const Quadrature<dim>& face_quadrature
+                = QProjector<dim>::project_to_all_faces
+                  (reference_face_quadrature);
+
+              for (unsigned int face = 0;
+                   face < GeometryInfo<dim>::faces_per_cell; ++face)
+                for (unsigned int q_point = 0; q_point < n_face_points;
+                      ++q_point)
+                  {
+                    this->generalized_support_points
+                    [face * n_face_points + q_point
+                      + GeometryInfo<dim>::lines_per_cell * n_edge_points]
+                    = face_quadrature.point
+                      (QProjector<dim>::DataSetDescriptor::face
+                       (face, true, false, false, n_face_points) + q_point);
+                  }
+
+                   // Create support points in the interior.
+              for (unsigned int q_point = 0; q_point < n_interior_points;
+                   ++q_point)
+                this->generalized_support_points[q_point + n_boundary_points]
+                  = quadrature.point (q_point);
+            }
+         
+          else
+            {
+              this->generalized_face_support_points.resize (4 * n_edge_points);
+              this->generalized_support_points.resize
+                (GeometryInfo<dim>::lines_per_cell * n_edge_points);
+
+              for (unsigned int q_point = 0; q_point < n_edge_points;
+                   ++q_point)
+                {
+                  for (unsigned int line = 0;
+                       line < GeometryInfo<dim - 1>::lines_per_cell; ++line)
+                    this->generalized_face_support_points[line * n_edge_points
+                                                          + q_point]
+                      = edge_quadrature.point
+                        (QProjector<dim - 1>::DataSetDescriptor::face
+                         (line, true, false, false, n_edge_points) + q_point);
+
+                  for (unsigned int i = 0; i < 2; ++i)
+                    for (unsigned int j = 0; j < 2; ++j)
+                      {
+                        this->generalized_support_points
+                          [q_point + (i + 4 * j) * n_edge_points]
+                          = Point<dim>
+                            (i, reference_edge_quadrature.point (q_point) (0),
+                             j);
+                        this->generalized_support_points
+                          [q_point + (i + 4 * j + 2) * n_edge_points]
+                          = Point<dim>
+                            (reference_edge_quadrature.point (q_point) (0),
+                             i, j);
+                        this->generalized_support_points
+                          [q_point + (i + 2 * (j + 4)) * n_edge_points]
+                          = Point<dim>
+                            (i, j,
+                             reference_edge_quadrature.point (q_point) (0));
+                      }
+                }
+            }
+          
+          break;
+        }
+      
       default:
-           Assert (false, ExcNotImplemented());
-    };
-  
-  return 0;
+        Assert (false, ExcNotImplemented ());
+    }
 }
 
 #endif
 
-#if deal_II_dimension == 1
-
-template <>
-Tensor<1,1>
-FE_Nedelec<1>::shape_grad_component (const unsigned int ,
-                                    const Point<1>    &,
-                                    const unsigned int ) const
-{
-  Assert (false, ExcNotImplemented());
-  return Tensor<1,1>();
-}
 
-#endif
-
-#if deal_II_dimension == 2
+#if deal_II_dimension == 1
 
+                   // Set the restriction matrices.
 template <>
-Tensor<1,2>
-FE_Nedelec<2>::shape_grad_component (const unsigned int i,
-                                    const Point<2>    &,
-                                    const unsigned int component) const
+void
+FE_Nedelec<1>::initialize_restriction ()
 {
-  const unsigned int dim = 2;
-  Assert (i<this->dofs_per_cell, ExcIndexRange(i,0,this->dofs_per_cell));
-  Assert (component < dim, ExcIndexRange (component, 0, dim));
-
-  switch (degree)
-    {
-                                      // first order Nedelec elements
-      case 1:
-      {
-                                        // on the unit cell, the
-                                        // gradients of these shape
-                                        // functions are constant, so
-                                        // we pack them into a table
-                                        // for simpler lookup
-                                        //
-                                        // the format is: first
-                                        // index=shape function
-                                        // number; second
-                                        // index=vector component,
-                                        // third index=component
-                                        // within gradient
-       static const double unit_gradients[4][2][2]
-         = { { {0., 0.}, {-1.,0.} },
-             { {0., 0.}, {+1.,0.} },
-             { {0.,-1.}, { 0.,0.} },
-             { {0.,+1.}, { 0.,0.} } };
-       return Tensor<1,dim>(unit_gradients[i][component]);
-      };
-
-                                       // no other degrees
-                                       // implemented
-      default:
-           Assert (false, ExcNotImplemented());
-    };
-  
-  return Tensor<1,dim>();
+                                  // there is only one refinement case in 1d,
+                                  // which is the isotropic one
+  for (unsigned int i = 0; i < GeometryInfo<1>::max_children_per_cell; ++i)
+    this->restriction[0][i].reinit(0, 0);
 }
 
 #endif
 
-#if deal_II_dimension == 3
-
-template <>
-Tensor<1,3>
-FE_Nedelec<3>::shape_grad_component (const unsigned int i,
-                                    const Point<3>    &p,
-                                    const unsigned int component) const
+                   // Restriction operator 
+template <int dim>
+void
+FE_Nedelec<dim>::initialize_restriction ()
 {
-  const unsigned int dim = 3;
-  Assert (i<this->dofs_per_cell, ExcIndexRange(i,0,this->dofs_per_cell));
-  Assert (component < dim, ExcIndexRange (component, 0, dim));
-
-  switch (degree)
+  switch (dim)
     {
-                                      // first order Nedelec elements
-      case 1:
-      {
-                                        // on the unit cell, the
-                                        // gradients of these shape
-                                        // functions are linear. we
-                                        // pack them into an array,
-                                        // knowing that it may be
-                                        // expensive to recompute the
-                                        // whole array each
-                                        // time. maybe some clever
-                                        // compiler can optimize this
-                                        // out, seeing that except
-                                        // for one element all the
-                                        // other ones are dead
-                                        // stores...
-                                        //
-                                        // the format is: first
-                                        // index=shape function
-                                        // number; second
-                                        // index=vector component,
-                                        // third index=component
-                                        // within gradient
-       const double x = p(0),
-                    y = p(1),
-                    z = p(2);
-       const double unit_gradients[12][3][3]
-         = { { {0,      0,      0}, {-(1-z), 0, -(1-x)}, {0, 0, 0} },
-             { {0,      0,      0}, { (1-z), 0,     -x}, {0, 0, 0} },
-             { {0, -(1-z), -(1-y)}, {0,      0,      0}, {0, 0, 0} },
-             { {0,  (1-z),     -y}, {0,      0,      0}, {0, 0, 0} },
-             
-             { {0,  0,     0}, {-z, 0, (1-x)}, {0, 0, 0} },
-             { {0,  0,     0}, { z, 0,     x}, {0, 0, 0} },
-             { {0, -z, (1-y)}, { 0, 0,     0}, {0, 0, 0} },
-             { {0,  z,     y}, { 0, 0,     0}, {0, 0, 0} },
-
-             { {0, 0, 0}, {0, 0, 0}, {-(1-y), -(1-x), 0} },
-             { {0, 0, 0}, {0, 0, 0}, { (1-y),     -x, 0} },
-             { {0, 0, 0}, {0, 0, 0}, {    -y,  (1-x), 0} },
-             { {0, 0, 0}, {0, 0, 0}, {     y,      x, 0} } };
-                                        // note: simple check whether
-                                        // this can at all be: build
-                                        // the sum over all these
-                                        // tensors. since the sum of
-                                        // the shape functions is a
-                                        // constant, the gradient
-                                        // must necessarily be
-                                        // zero. this is in fact the
-                                        // case here, so test
-                                        // successfull
-       return Tensor<1,dim>(unit_gradients[i][component]);
-      };
-
-                                       // no other degrees
-                                       // implemented
+      case 2:
+        {
+          const unsigned int n_boundary_dofs
+            = GeometryInfo<dim>::lines_per_cell * this->degree;
+          const unsigned int n_dofs
+            = (GeometryInfo<dim>::lines_per_cell + 2 * deg) * this->degree;
+
+          for (unsigned int ref = RefinementCase<dim>::cut_x;
+               ref <= RefinementCase<dim>::isotropic_refinement; ++ref)
+            {
+              const unsigned int index = ref - 1;
+              
+              switch (ref)
+                {
+                  case RefinementCase<dim>::cut_x:
+                    {
+                      for (unsigned int child = 0;
+                           child
+                             < GeometryInfo<dim>::n_children
+                               (RefinementCase<dim> (ref)); ++child)
+                        {
+                          for (unsigned int dof = child * this->degree;
+                               dof < (child + 1) * this->degree; ++dof)
+                            this->restriction[index][child] (dof, dof) = 1.0;
+
+                          for (unsigned int dof = 2 * this->degree;
+                               dof < n_dofs; ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.5;
+                        }
+
+                      break;
+                    }
+
+                  case RefinementCase<dim>::cut_y:
+                    {
+                      for (unsigned int child = 0;
+                           child
+                             < GeometryInfo<dim>::n_children
+                               (RefinementCase<dim> (ref)); ++child)
+                        {
+                          for (unsigned int dof = 0; dof < 2 * this->degree;
+                               ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.5;
+
+                          for (unsigned int dof = (child + 2) * this->degree;
+                               dof < (child + 3) * this->degree; ++dof)
+                            this->restriction[index][child] (dof, dof) = 1.0;
+
+                          for (unsigned int dof = n_boundary_dofs;
+                               dof < n_dofs; ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.5;
+                        }
+
+                      break;
+                    }
+
+                  case RefinementCase<dim>::isotropic_refinement:
+                    {
+                                // First we set the values for
+                                // the boundary dofs of every
+                                // child.
+                                
+                                 // child 0
+                      for (unsigned int dof = 0; dof <= deg; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][0]
+                            (dof + 2 * i * this->degree,
+                             dof + 2 * i * this->degree) = 0.5;
+
+                                 // child 1
+                      for (unsigned int dof = this->degree;
+                           dof < 3 * this->degree; ++dof)
+                        this->restriction[index][1] (dof, dof) = 0.5;
+
+                                 // child 2
+                      for (unsigned int dof = 0; dof <= deg; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][2]
+                            (dof + 3 * i * this->degree,
+                             dof + 3 * i * this->degree) = 0.5;
+
+                                 // child 3
+                      for (unsigned int dof = this->degree;
+                           dof < 2 * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][3]
+                            (dof + 2 * i * this->degree,
+                             dof + 2 * i * this->degree) = 0.5;
+
+                                 // The values for the interior
+                                 // dofs are the same for
+                                 // every child.
+                      for (unsigned int child = 0;
+                           child
+                             < GeometryInfo<dim>::n_children
+                               (RefinementCase<dim> (ref)); ++child)
+                        for (unsigned int dof = n_boundary_dofs; dof < n_dofs;
+                             ++dof)
+                          this->restriction[index][child] (dof, dof) = 0.25;
+                      
+                      break;
+                    }
+                  
+                  default:
+                    Assert (false, ExcNotImplemented ());
+                }
+            }
+
+          break;
+        }
+
+      case 3:
+        {
+          const unsigned int n_edge_dofs
+            = GeometryInfo<dim>::lines_per_cell * deg;
+          const unsigned int n_boundary_dofs
+            = n_edge_dofs
+              + 2 * GeometryInfo<dim>::faces_per_cell * deg * this->degree;
+          const unsigned int n_dofs
+            = (GeometryInfo<dim>::lines_per_cell
+               + (2 * GeometryInfo<dim>::faces_per_cell + 3 * deg) * deg)
+              * this->degree;
+
+          for (unsigned int ref = RefinementCase<dim>::cut_x;
+               ref <= RefinementCase<dim>::isotropic_refinement; ++ref)
+            {
+              const unsigned int index = ref - 1;
+              
+              switch (ref)
+                {
+                  case RefinementCase<3>::cut_x:
+                    {
+                      for (unsigned int child = 0;
+                           child
+                             < GeometryInfo<dim>::n_children
+                               (RefinementCase<dim> (ref)); ++child)
+                        {
+                                    // First we set the values for
+                                    // the edge dofs.
+                          for (unsigned int dof = 0; dof <= deg; ++dof)
+                            {
+                              for (unsigned int i = 0; i < 3; ++i)
+                                this->restriction[index][child]
+                                  (dof + (child + 4 * i) * this->degree,
+                                   dof + (child + 4 * i) * this->degree)
+                                  = 1.0;
+
+                              this->restriction[index][child]
+                                (dof + (child + 10) * this->degree,
+                                 dof + (child + 10) * this->degree) = 1.0;
+                            }
+
+                          for (unsigned int dof = 2 * this->degree;
+                               dof < 4 * this->degree; ++dof)
+                            for (unsigned int i = 0; i < 2; ++i)
+                              this->restriction[index][child]
+                                (dof + 4 * i * this->degree,
+                                 dof + 4 * i * this->degree) = 0.5;
+
+                                    // Then we set the values for
+                                    // the face and the interior
+                                    // dofs.
+                          for (unsigned int dof
+                                 = n_edge_dofs
+                                   + 2 * child * deg * this->degree;
+                               dof
+                                 < n_edge_dofs
+                                   + 2 * (child + 1) * deg * this->degree;
+                               ++dof)
+                            this->restriction[index][child] (dof, dof) = 1.0;
+
+                          for (unsigned int dof
+                                 = n_edge_dofs + 4 * deg * this->degree;
+                               dof < n_dofs; ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.5;
+                        }
+
+                      break;
+                    }
+
+                  case RefinementCase<3>::cut_y:
+                    {
+                      for (unsigned int child = 0;
+                           child
+                             < GeometryInfo<dim>::n_children
+                               (RefinementCase<dim> (ref)); ++child)
+                        {
+                                    // First we set the values for
+                                    // the edge dofs.
+                          for (unsigned int dof = 0; dof < 2 * this->degree;
+                               ++dof)
+                            {
+                              for (unsigned int i = 0; i < 2; ++i)
+                                this->restriction[index][child]
+                                  (dof + 4 * i * this->degree,
+                                   dof + 4 * i * this->degree) = 0.5;
+
+                              this->restriction[index][child]
+                                (dof + 2 * (child + 4) * this->degree,
+                                 dof + 2 * (child + 4) * this->degree) = 1.0;
+                            }
+
+                          for (unsigned int dof = (child + 2) * this->degree;
+                               dof < (child + 3) * this->degree; ++dof)
+                            for (unsigned int i = 0; i < 2; ++i)
+                              this->restriction[index][child]
+                                (dof + 4 * i * this->degree,
+                                 dof + 4 * i * this->degree) = 1.0;
+
+                                 // Then we set the values for
+                                 // the face and the interior
+                                 // dofs.
+                          for (unsigned int dof = n_edge_dofs;
+                               dof < n_edge_dofs + 4 * deg * this->degree;
+                               ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.5;
+
+                          for (unsigned int dof
+                                 = n_edge_dofs
+                                   + 2 * (child + 2) * deg * this->degree;
+                               dof
+                                 < n_edge_dofs
+                                   + 2 * (child + 3) * deg * this->degree;
+                               ++dof)
+                            this->restriction[index][child] (dof, dof) = 1.0;
+
+                          for (unsigned int dof
+                                 = n_edge_dofs + 8 * deg * this->degree;
+                               dof < n_dofs; ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.5;
+                        }
+
+                      break;
+                    }
+
+                  case RefinementCase<3>::cut_xy:
+                    {
+                                 // child 0
+                      for (unsigned int dof = 0; dof <= deg; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 4; ++i)
+                            this->restriction[index][0]
+                              (dof + 2 * i * this->degree,
+                               dof + 2 * i * this->degree) = 0.5;
+
+                          this->restriction[index][0] (dof + 8 * this->degree,
+                                                       dof + 8 * this->degree)
+                            = 1.0;
+                        }
+
+                      for (unsigned int dof = n_edge_dofs;
+                           dof < n_edge_dofs + 2 * deg * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][0]
+                            (dof + 4 * i * deg * this->degree,
+                             dof + 4 * i * deg * this->degree) = 0.5;
+
+                                 // child 1
+                      for (unsigned int dof = this->degree;
+                           dof < 3 * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][1]
+                            (dof + 4 * i * this->degree,
+                             dof + 4 * i * this->degree) = 0.5;
+
+                      for (unsigned int dof = 9 * this->degree;
+                           dof < 10 * this->degree; ++dof)
+                        this->restriction[2][1] (dof, dof) = 1.0;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 2 * deg * this->degree;
+                           dof < n_edge_dofs + 6 * deg * this->degree;
+                           ++dof)
+                        this->restriction[2][1] (dof, dof) = 0.5;
+
+                                 // child 2
+                      for (unsigned int dof = 0; dof <= deg; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 2; ++i)
+                            this->restriction[index][2]
+                              (dof + 7 * i * this->degree,
+                               dof + 7 * i * this->degree) = 0.5;
+
+                            this->restriction[index][2]
+                              (dof + 10 * this->degree,
+                               dof + 10 * this->degree) = 1.0;
+                        }
+
+                      for (unsigned int dof = 3 * this->degree;
+                           dof < 5 * this->degree; ++dof)
+                        this->restriction[index][2] (dof, dof) = 0.5;
+
+                      for (unsigned int dof = n_edge_dofs;
+                           dof < n_edge_dofs + 2 * deg * this->degree;
+                           ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][2]
+                            (dof + 6 * i * deg * this->degree,
+                             dof + 6 * i * deg * this->degree) = 0.5;
+
+                                 // child 3
+                      for (unsigned int dof = this->degree;
+                           dof < 2 * this->degree; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 4; ++i)
+                            this->restriction[index][3]
+                              (dof + 2 * i * this->degree,
+                               dof + 2 * i * this->degree) = 0.5;
+
+                          this->restriction[index][3]
+                            (dof + 10 * this->degree,
+                             dof + 10 * this->degree) = 1.0;
+                        }
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 2 * deg * this->degree;
+                           dof < n_edge_dofs + 4 * deg * this->degree;
+                           ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][3]
+                            (dof + 4 * i * deg * this->degree,
+                             dof + 4 * i * deg * this->degree) = 0.5;
+
+                                 // Some values are the same
+                                 // on every child.
+                      for (unsigned int child = 0;
+                           child
+                             < GeometryInfo<dim>::n_children
+                              (RefinementCase<dim> (ref)); ++child)
+                        for (unsigned int dof
+                               = n_edge_dofs + 8 * deg * this->degree;
+                             dof < n_dofs; ++dof)
+                          this->restriction[index][child] (dof, dof) = 0.25;
+
+                      break;
+                    }
+
+                  case RefinementCase<3>::cut_z:
+                    {
+                      for (unsigned int child = 0;
+                           child
+                             < GeometryInfo<dim>::n_children
+                               (RefinementCase<dim> (ref)); ++child)
+                        {
+                          for (unsigned int dof = 4 * child * this->degree;
+                               dof < 4 * (child + 1) * this->degree; ++dof)
+                            for (unsigned int i = 0; i < 2; ++i)
+                              this->restriction[index][child]
+                                (dof + 4 * (2 - child) * i * this->degree,
+                                 dof + 4 * (2 - child) * i * this->degree)
+                                = 1.0 / (i + 1);
+
+                          for (unsigned int dof = n_edge_dofs;
+                               dof < n_edge_dofs + 8 * deg * this->degree;
+                               ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.5;
+
+                          for (unsigned int dof
+                                 = n_edge_dofs
+                                   + 2 * (child + 4) * deg * this->degree;
+                               dof
+                                 <  n_edge_dofs
+                                    + 2 * (child + 5) * deg * this->degree;
+                               ++ dof)
+                            this->restriction[index][child] (dof, dof) = 1.0;
+
+                          for (unsigned int dof = n_boundary_dofs;
+                               dof < n_dofs; ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.5;
+                        }
+
+                      break;
+                    }
+
+                  case RefinementCase<3>::cut_xz:
+                    {
+                                 // child 0
+                      for (unsigned int dof = 0; dof <= deg; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 2; ++i)
+                            this->restriction[index][0]
+                              (dof + 2 * (i + 4) * this->degree,
+                               dof + 2 * (i + 4) * this->degree) = 0.5;
+
+                          this->restriction[index][0] (dof, dof) = 1.0;
+                        }
+
+                      for (unsigned int dof = 2 * this->degree;
+                           dof < 4 * this->degree; ++dof)
+                        this->restriction[index][0] (dof, dof) = 0.5;
+
+                      for (unsigned int dof = n_edge_dofs;
+                           dof < n_edge_dofs + 2 * deg * this->degree;
+                           ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][0]
+                            (dof + 8 * i * deg * this->degree,
+                             dof + 8 * i * deg * this->degree) = 0.5;
+
+                                 // child 1
+                      for (unsigned int dof = 4 * this->degree;
+                           dof < 5 * this->degree; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 2; ++i)
+                            this->restriction[index][1]
+                              (dof + 2 * (i + 2) * this->degree,
+                               dof + 2 * (i + 2) * this->degree) = 0.5;
+
+                          this->restriction[index][1] (dof, dof) = 1.0;
+                        }
+
+                      for (unsigned int dof = 6 * this->degree;
+                           dof < 8 * this->degree; ++dof)
+                        this->restriction[index][1] (dof, dof) = 0.5;
+
+                      for (unsigned int dof = n_edge_dofs;
+                           dof < n_edge_dofs + 2 * deg * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][1]
+                            (dof + 10 * i * deg * this->degree,
+                             dof + 10 * i * deg * this->degree) = 0.5;
+
+                                 // child 2
+                      for (unsigned int dof = this->degree;
+                           dof < 2 * this->degree; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 2; ++i)
+                            this->restriction[index][2]
+                              (dof + 2 * (i + 4) * this->degree,
+                               dof + 2 * (i + 4) * this->degree) = 0.5;
+
+                          this->restriction[index][2] (dof, dof) = 1.0;
+                        }
+
+                      for (unsigned int dof = 2 * this->degree;
+                           dof < 4 * this->degree; ++dof)
+                        this->restriction[index][2] (dof, dof) = 0.5;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 2 * deg * this->degree;
+                           dof < n_edge_dofs + 4 * deg * this->degree;
+                           ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][2]
+                            (dof + 6 * i * deg * this->degree,
+                             dof + 6 * i * deg * this->degree) = 0.5;
+
+                                 // child 3
+                      for (unsigned int dof = 5 * this->degree;
+                           dof < 6 * this->degree; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 2; ++i)
+                            this->restriction[index][3]
+                              (dof + 2 * (i + 2) * this->degree,
+                               dof + 2 * (i + 2) * this->degree) = 0.5;
+
+                          this->restriction[index][3] (dof, dof) = 1.0;
+                        }
+
+                      for (unsigned int dof = 6 * this->degree;
+                           dof < 8 * this->degree; ++dof)
+                        this->restriction[index][3] (dof, dof) = 0.5;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 2 * deg * this->degree;
+                           dof < n_edge_dofs + 4 * deg * this->degree;
+                           ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][3]
+                            (dof + 8 * i * deg * this->degree,
+                             dof + 8 * i * deg * this->degree) = 0.5;
+
+                                 // Some values are the same
+                                 // on every child.
+                      for (unsigned int child = 0;
+                           child
+                             < GeometryInfo<dim>::n_children
+                              (RefinementCase<dim> (ref)); ++child)
+                        {
+                          for (unsigned int dof
+                                 = n_edge_dofs + 4 * deg * this->degree;
+                               dof < n_edge_dofs + 8 * deg * this->degree;
+                               ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.25;
+
+                          for (unsigned int dof = n_boundary_dofs;
+                               dof < n_dofs; ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.25;
+                        }
+
+                      break;
+                    }
+
+                  case RefinementCase<3>::cut_yz:
+                    {
+                                 // child 0
+                      for (unsigned int dof = 0; dof < 2 * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][0]
+                            (dof + 8 * i * this->degree,
+                             dof + 8 * i * this->degree) = 0.5;
+
+                      for (unsigned int dof = 2 * this->degree;
+                           dof < 3 * this->degree; ++dof)
+                        this->restriction[index][0] (dof, dof) = 1.0;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 4 * deg * this->degree;
+                           dof < n_edge_dofs + 6 * deg * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][0]
+                            (dof + 4 * i * deg * this->degree,
+                             dof + 4 * i * deg * this->degree) = 0.5;
+
+                                 // child 1
+                      for (unsigned int dof = 0; dof < 2 * this->degree;
+                           ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][1]
+                            (dof + 10 * i * this->degree,
+                             dof + 10 * i * this->degree) = 0.5;
+
+                      for (unsigned int dof = 3 * this->degree;
+                           dof < 4 * this->degree; ++dof)
+                        this->restriction[index][1] (dof, dof) = 1.0;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 6 * deg * this->degree;
+                           dof < n_edge_dofs + 10 * deg * this->degree; ++dof)
+                        this->restriction[index][1] (dof, dof) = 0.5;
+
+                                 // child 2
+                      for (unsigned int dof = 4 * this->degree;
+                           dof < 6 * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][2]
+                            (dof + 4 * i * this->degree,
+                             dof + 4 * i * this->degree) = 0.5;
+
+                      for (unsigned int dof = 6 * this->degree;
+                           dof < 7 * this->degree; ++dof)
+                        this->restriction[index][2] (dof, dof) = 1.0;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 4 * deg * this->degree;
+                           dof < n_edge_dofs + 6 * deg * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][2]
+                            (dof + 6 * i * deg * this->degree,
+                             dof + 6 * i * deg * this->degree) = 0.5;
+
+                                 // child 3
+                      for (unsigned int dof = 4 * this->degree;
+                           dof < 6 * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][3]
+                            (dof + 6 * i * this->degree,
+                             dof + 6 * i * this->degree) = 0.5;
+
+                      for (unsigned int dof = 7 * this->degree;
+                           dof < 8 * this->degree; ++dof)
+                        this->restriction[index][3] (dof, dof) = 1.0;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 6 * deg * this->degree;
+                           dof < n_edge_dofs + 8 * deg * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 2; ++i)
+                          this->restriction[index][3]
+                            (dof + 4 * i * deg * this->degree,
+                             dof + 4 * i * deg * this->degree) = 0.5;
+
+                                 // Some values are the same
+                                 // on every child.
+                      for (unsigned int child = 0;
+                           child
+                             < GeometryInfo<dim>::n_children
+                              (RefinementCase<dim> (ref)); ++child)
+                        {
+                          for (unsigned int dof = n_edge_dofs;
+                               dof < n_edge_dofs + 4 * deg * this->degree;
+                               ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.25;
+
+                          for (unsigned int dof = n_boundary_dofs;
+                               dof < n_dofs; ++dof)
+                            this->restriction[index][child] (dof, dof) = 0.25;
+                        }
+
+                      break;
+                    }
+
+                  case RefinementCase<3>::isotropic_refinement:
+                    {
+                                // Set the values for the
+                                // boundary dofs.
+                                
+                                 // child 0
+                      for (unsigned int dof = 0; dof <= deg; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 2; ++i)
+                            this->restriction[index][0]
+                              (dof + 2 * i * this->degree,
+                               dof + 2 * i * this->degree) = 0.5;
+
+                          this->restriction[index][0] (dof + 8 * this->degree,
+                                                       dof + 8 * this->degree)
+                            = 0.5;
+                        }
+
+                      for (unsigned int dof = n_edge_dofs;
+                           dof < n_edge_dofs + 2 * deg * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 3; ++i)
+                          this->restriction[index][0]
+                            (dof + 4 * i * deg * this->degree,
+                             dof + 4 * i * deg * this->degree) = 0.25;
+
+                                 // child 1
+                      for (unsigned int dof = this->degree;
+                           dof < 3 * this->degree; ++dof)
+                        this->restriction[index][1] (dof, dof) = 0.5;
+
+                      for (unsigned int dof = 9 * this->degree;
+                           dof < 10 * this->degree; ++dof)
+                        this->restriction[index][1] (dof, dof) = 0.5;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 2 * deg * this->degree;
+                           dof < n_edge_dofs + 6 * deg * this->degree; ++dof)
+                        this->restriction[index][1] (dof, dof) = 0.25;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 8 * deg * this->degree;
+                           dof < n_edge_dofs + 10 * deg * this->degree; ++dof)
+                        this->restriction[index][1] (dof, dof) = 0.25;
+
+                                 // child 2
+                      for (unsigned int dof = 0; dof <= deg; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 2; ++i)
+                            this->restriction[index][2]
+                              (dof + 3 * i * this->degree,
+                               dof + 3 * i * this->degree) = 0.5;
+
+                          this->restriction[index][2] (dof + 10 * this->degree,
+                                                       dof + 10 * this->degree)
+                            = 0.5;
+                        }
+
+                      for (unsigned int dof = n_edge_dofs;
+                           dof < n_edge_dofs + 2 * deg * this->degree; ++dof)
+                        this->restriction[index][2] (dof, dof) = 0.25;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 6 * deg * this->degree;
+                           dof < n_edge_dofs + 10 * deg * this->degree; ++dof)
+                        this->restriction[index][2] (dof, dof) = 0.25;
+
+                                 // child 3
+                      for (unsigned int dof = this->degree;
+                           dof < 2 * this->degree; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 2; ++i)
+                            this->restriction[index][3]
+                              (dof + 2 * i * this->degree,
+                               dof + 2 * i * this->degree) = 0.5;
+
+                          this->restriction[index][3]
+                            (dof + 10 * this->degree, dof + 10 * this->degree)
+                             = 0.5;
+                        }
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 2 * deg * this->degree;
+                           dof < n_edge_dofs + 4 * deg * this->degree; ++dof)
+                        this->restriction[index][3] (dof, dof) = 0.25;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 6 * deg * this->degree;
+                           dof < n_edge_dofs + 10 * deg * this->degree; ++dof)
+                        this->restriction[index][3] (dof, dof) = 0.25;
+
+                                 // child 4
+                      for (unsigned int dof = 4 * this->degree;
+                           dof < 5 * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 3; ++i)
+                          this->restriction[index][4]
+                            (dof + 2 * i * this->degree,
+                             dof + 2 * i * this->degree) = 0.5;
+
+                      for (unsigned int dof = n_edge_dofs;
+                           dof < n_edge_dofs + 2 * deg * this->degree; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 2; ++i)
+                            this->restriction[index][4]
+                              (dof + 4 * i * deg * this->degree,
+                               dof + 4 * i * deg * this->degree) = 0.25;
+
+                          this->restriction[index][4]
+                            (dof + 10 * deg * this->degree,
+                             dof + 10 * deg * this->degree) = 0.25;
+                        }
+
+                                 // child 5
+                      for (unsigned int dof = 5 * this->degree;
+                           dof < 7 * this->degree; ++dof)
+                        this->restriction[index][5] (dof, dof) = 0.5;
+
+                      for (unsigned int dof = 9 * this->degree;
+                           dof < 10 * this->degree; ++dof)
+                        this->restriction[index][5] (dof, dof) = 0.5;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 2 * deg * this->degree;
+                           dof < n_edge_dofs + 6 * deg * this->degree; ++dof)
+                        this->restriction[index][5] (dof, dof) = 0.25;
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 10 * deg * this->degree;
+                           dof < n_boundary_dofs; ++dof)
+                        this->restriction[index][5] (dof, dof) = 0.25;
+
+                                 // child 6
+                      for (unsigned int dof = 4 * this->degree;
+                           dof < 5 * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 3; ++i)
+                          this->restriction[index][6]
+                            (dof + 3 * i * this->degree,
+                             dof + 3 * i * this->degree) = 0.5;
+
+                      for (unsigned int dof = n_edge_dofs;
+                           dof < n_edge_dofs + 2 * deg * this->degree; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 2; ++i)
+                            this->restriction[index][6]
+                              (dof + 6 * i * deg * this->degree,
+                               dof + 6 * i * deg * this->degree) = 0.25;
+
+                          this->restriction[index][6]
+                            (dof + 10 * deg * this->degree,
+                             dof + 10 * deg * this->degree) = 0.25;
+                        }
+
+                                 // child 7
+                      for (unsigned int dof = 5 * this->degree;
+                           dof < 6 * this->degree; ++dof)
+                        {
+                          for (unsigned int i = 0; i < 2; ++i)
+                            this->restriction[index][7]
+                              (dof + 2 * i * this->degree,
+                               dof + 2 * i * this->degree) = 0.5;
+
+                          this->restriction[index][7] (dof + 6 * this->degree,
+                                                       dof + 6 * this->degree)
+                            = 0.5;
+                        }
+
+                      for (unsigned int dof
+                             = n_edge_dofs + 2 * deg * this->degree;
+                           dof < n_edge_dofs + 4 * deg * this->degree; ++dof)
+                        for (unsigned int i = 0; i < 3; ++i)
+                          this->restriction[index][7]
+                            (dof + 4 * i * deg * this->degree,
+                             dof + 4 * i * deg * this->degree) = 0.25;
+
+                                 // The interior values are the
+                                 // same on every child.
+                      for (unsigned int child = 0;
+                           child
+                             < GeometryInfo<dim>::n_children
+                              (RefinementCase<dim> (ref)); ++child)
+                        for (unsigned int dof = n_boundary_dofs; dof < n_dofs;
+                             ++dof)
+                          this->restriction[index][child] (dof, dof) = 0.125;
+                      
+                      break;
+                    }
+                  
+                  default:
+                    Assert (false, ExcNotImplemented ());
+                }
+            }
+          
+          break;
+        }
+        
       default:
-           Assert (false, ExcNotImplemented());
-    };
-  
-  return Tensor<1,dim>();
+        Assert (false, ExcNotImplemented ());
+    }
 }
 
-#endif
-
 
 #if deal_II_dimension == 1
 
 template <>
-Tensor<2,1>
-FE_Nedelec<1>::shape_grad_grad_component (const unsigned int ,
-                                         const Point<1>    &,
-                                         const unsigned int ) const
-{
-  Assert (false, ExcNotImplemented());
-  return Tensor<2,1>();
-}
-
-#endif
-
-
-#if deal_II_dimension == 2
-
-template <>
-Tensor<2,2>
-FE_Nedelec<2>::shape_grad_grad_component (const unsigned int i,
-                                         const Point<2> &/*p*/,
-                                         const unsigned int component) const
+std::vector<unsigned int>
+FE_Nedelec<1>::get_dpo_vector (const unsigned int degree)
 {
-  const unsigned int dim = 2;
-  Assert (i<this->dofs_per_cell, ExcIndexRange(i,0,this->dofs_per_cell));
-  Assert (component < dim, ExcIndexRange (component, 0, dim));
-
-  switch (degree)
-    {
-                                      // first order Nedelec
-                                      // elements. their second
-                                      // derivatives on the unit cell
-                                      // are zero
-      case 1:
-      {
-       return Tensor<2,dim>();
-      };
+  std::vector<unsigned int> dpo (2);
 
-                                       // no other degrees
-                                       // implemented
-      default:
-           Assert (false, ExcNotImplemented());
-    };
-
-  return Tensor<2,dim>();
+  dpo[0] = 1;
+  dpo[1] = degree;
+  return dpo;
 }
 
 #endif
 
-#if deal_II_dimension == 3
 
-template <>
-Tensor<2,3>
-FE_Nedelec<3>::shape_grad_grad_component (const unsigned int i,
-                                         const Point<3>    &/*p*/,
-                                         const unsigned int component) const
+template <int dim>
+std::vector<unsigned int>
+FE_Nedelec<dim>::get_dpo_vector (const unsigned int degree)
 {
-  const unsigned int dim = 3;
-  Assert (i<this->dofs_per_cell, ExcIndexRange(i,0,this->dofs_per_cell));
-  Assert (component < dim, ExcIndexRange (component, 0, dim));
+  std::vector<unsigned int> dpo (dim + 1);
 
-  switch (degree)
-    {
-                                      // first order Nedelec
-                                      // elements. their second
-                                      // derivatives on the unit cell
-                                      // are constant, but non-zero
-      case 1:
-      {
-                                        // the format is: first
-                                        // index=shape function
-                                        // number; second
-                                        // index=vector component,
-                                        // third and fourth
-                                        // index=component within
-                                        // second derivative
-       static const double unit_grad_grads[12][3][3][3]
-         = {
-               { { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0, 1}, {0, 0, 0}, {1, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} } },
-
-               { { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0,-1}, {0, 0, 0}, {-1, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} } },
-               
-               { { {0, 0, 0}, {0, 0, 1}, {0, 1, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} } },
-
-               { { {0, 0, 0}, {0, 0,-1}, {0,-1, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} } },
-
-               { { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0,-1}, {0, 0, 0}, {-1, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} } },
-
-               { { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0, 1}, {0, 0, 0}, {1, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} } },
-
-               { { {0, 0, 0}, {0, 0,-1}, {0,-1, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} } },
-
-               { { {0, 0, 0}, {0, 0, 1}, {0, 1, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} } },
-
-               { { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 1, 0}, {1, 0, 0}, {0, 0, 0} } },
-
-               { { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0,-1, 0}, {-1, 0, 0}, {0, 0, 0} } },
-
-               { { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0,-1, 0}, {-1, 0, 0}, {0, 0, 0} } },
-
-               { { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} },
-                 { {0, 1, 0}, {1, 0, 0}, {0, 0, 0} } }
-         };
-
-       return Tensor<2,dim>(unit_grad_grads[i][component]);
-      };
-
-                                       // no other degrees
-                                       // implemented
-      default:
-           Assert (false, ExcNotImplemented());
-    };
+  dpo[0] = 0;
+  dpo[1] = degree + 1;
+  dpo[2] = 2 * degree * (degree + 1);
 
-  return Tensor<2,dim>();
-}
+  if (dim == 3)
+     dpo[3] = 3 * degree * degree * (degree + 1);
 
-#endif
+  return dpo;
+}
 
 //---------------------------------------------------------------------------
-// Auxiliary functions
+// Data field initialization
 //---------------------------------------------------------------------------
 
-
-
-template <int dim, int spacedim>
-void
-FE_Nedelec<dim,spacedim>::initialize_constraints ()
+                                 // Chech wheter a given shape
+                                 // function has support on a
+                                 // given face.
+                                 
+                                 // We just switch through the
+                                 // faces of the cell and return
+                                 // true, if the shape function
+                                 // has support on the face
+                                 // and false otherwise.
+template <int dim>
+bool
+FE_Nedelec<dim>::has_support_on_face (const unsigned int shape_index,
+                                      const unsigned int face_index) const
 {
-                                  // copy constraint matrices if they
-                                  // are defined. otherwise leave
-                                  // them at zero size
-  if (degree<Matrices::n_constraint_matrices+1)
-    {
-      this->interface_constraints.
-        TableBase<2,double>::reinit (this->interface_constraints_size());
-      this->interface_constraints.fill (Matrices::constraint_matrices[degree-1]);
-    };
-}
-
-
+  Assert (shape_index < this->dofs_per_cell,
+          ExcIndexRange (shape_index, 0, this->dofs_per_cell));
+  Assert (face_index < GeometryInfo<dim>::faces_per_cell,
+          ExcIndexRange (face_index, 0, GeometryInfo<dim>::faces_per_cell));
 
-template <int dim, int spacedim>
-void
-FE_Nedelec<dim,spacedim>::initialize_embedding ()
-{
-  unsigned int iso=RefinementCase<dim>::isotropic_refinement-1;
-  if ((degree < Matrices::n_embedding_matrices+1) &&
-      (Matrices::embedding[degree-1][0] != 0))
-    for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_cell; ++c)
-      {
-                                         // copy
-        this->prolongation[iso][c].reinit (this->dofs_per_cell,
-                                      this->dofs_per_cell);
-        this->prolongation[iso][c].fill (Matrices::embedding[degree-1][c]);
-                                         // and make sure that the row
-                                         // sum is 0.5 (for usual
-                                         // elements, the row sum must
-                                         // be 1, but here the shape
-                                         // function is multiplied by
-                                         // the inverse of the
-                                         // Jacobian, which introduces
-                                         // a factor of 1/2 when going
-                                         // from mother to child)
-        for (unsigned int row=0; row<this->dofs_per_cell; ++row)
+  switch (dim)
+    {
+      case 2:
+        switch (face_index)
           {
-            double sum = 0;
-            for (unsigned int col=0; col<this->dofs_per_cell; ++col)
-              sum += this->prolongation[iso][c](row,col);
-            Assert (std::fabs(sum-.5) < 1e-14,
-                    ExcInternalError());
-          };
-      };
-}
+            case 0:
+              if (!((shape_index > deg) && (shape_index < 2 * this->degree)))
+                return true;
+               
+              else
+                return false;
+
+             case 1:
+               if ((shape_index > deg) &&
+                   (shape_index
+                      < GeometryInfo<2>::lines_per_cell * this->degree))
+                 return true;
+               
+               else
+                 return false;
+
+             case 2:
+               if (shape_index < 3 * this->degree)
+                 return true;
+               
+               else
+                 return false;
+
+             case 3:
+               if (!((shape_index >= 2 * this->degree) &&
+                     (shape_index < 3 * this->degree)))
+                 return true;
+               
+               else
+                 return false;
+             
+             default:
+               {
+                 Assert (false, ExcNotImplemented ());
+                 return false;
+               }
+          }
+
+      case 3:
+        switch (face_index)
+          {
+            case 0:
+              if (((shape_index > deg) && (shape_index < 2 * this->degree)) ||
+                  ((shape_index >= 5 * this->degree) &&
+                   (shape_index < 6 * this->degree)) ||
+                  ((shape_index >= 9 * this->degree) &&
+                   (shape_index < 10 * this->degree)) ||
+                  ((shape_index >= 11 * this->degree) &&
+                   (shape_index
+                      < GeometryInfo<3>::lines_per_cell * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 2 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 5 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 6 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 7 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 8 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 9 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 10 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 11 * deg)
+                        * this->degree)))
+                return false;
+               
+              else
+                return true;
+
+            case 1:
+              if (((shape_index > deg) && (shape_index < 4 * this->degree)) ||
+                  ((shape_index >= 5 * this->degree) &&
+                   (shape_index < 8 * this->degree)) ||
+                  ((shape_index >= 9 * this->degree) &&
+                   (shape_index < 10 * this->degree)) ||
+                  ((shape_index >= 11 * this->degree) &&
+                   (shape_index
+                      < GeometryInfo<3>::lines_per_cell * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 2 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 4 * deg)
+                        * this->degree)) ||
+                   ((shape_index
+                       >= (GeometryInfo<3>::lines_per_cell + 5 * deg)
+                          * this->degree) &&
+                    (shape_index
+                       < (GeometryInfo<3>::lines_per_cell + 6 * deg)
+                         * this->degree)) ||
+                   ((shape_index
+                       >= (GeometryInfo<3>::lines_per_cell + 7 * deg)
+                          * this->degree) &&
+                    (shape_index
+                       < (GeometryInfo<3>::lines_per_cell + 8 * deg)
+                         * this->degree)) ||
+                   ((shape_index
+                       >= (GeometryInfo<3>::lines_per_cell + 9 * deg)
+                          * this->degree) &&
+                    (shape_index
+                       < (GeometryInfo<3>::lines_per_cell + 10 * deg)
+                         * this->degree)) ||
+                   ((shape_index
+                       >= (GeometryInfo<3>::lines_per_cell + 11 * deg)
+                          * this->degree) &&
+                    (shape_index
+                       < (GeometryInfo<3>::lines_per_cell + 12 * deg)
+                         * this->degree)))
+                return true;
+               
+              else
+                return false;
 
+            case 2:
+              if ((shape_index < 3 * this->degree) ||
+                  ((shape_index >= 4 * this->degree) &&
+                   (shape_index < 7 * this->degree)) ||
+                  ((shape_index >= 8 * this->degree) &&
+                   (shape_index < 10 * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 2 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 3 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 6 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 8 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 9 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 10 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 11 * deg)
+                        * this->degree)))
+                return true;
+               
+              else
+                return false;
 
+            case 3:
+              if ((shape_index < 2 * this->degree) ||
+                  ((shape_index >= 3 * this->degree) &&
+                   (shape_index < 6 * this->degree)) ||
+                  ((shape_index >= 7 * this->degree) &&
+                   (shape_index < 8 * this->degree)) ||
+                  ((shape_index >= 10 * this->degree) &&
+                   (shape_index
+                      < GeometryInfo<3>::lines_per_cell * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 2 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 3 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 4 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 6 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 9 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 10 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 11 * deg)
+                        * this->degree)))
+                return true;
+               
+              else
+                return false;
+
+            case 4:
+              if ((shape_index < 4 * this->degree) ||
+                  ((shape_index >= 8 * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 2 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 3 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 4 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 5 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 6 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 7 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 8 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 10 * deg)
+                        * this->degree)))
+                return true;
+               
+              else
+                return false;
+
+            case 5:
+              if (((shape_index >= 4 * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 2 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 3 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 4 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 5 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 6 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 7 * deg)
+                        * this->degree)) ||
+                  ((shape_index
+                      >= (GeometryInfo<3>::lines_per_cell + 10 * deg)
+                         * this->degree) &&
+                   (shape_index
+                      < (GeometryInfo<3>::lines_per_cell + 12 * deg)
+                        * this->degree)))
+                return true;
+               
+              else
+                return false;
+            
+            default:
+              {
+                Assert (false, ExcNotImplemented ());
+                return false;
+              }
+          }
 
-template <int dim, int spacedim>
-void
-FE_Nedelec<dim,spacedim>::initialize_restriction ()
-{
-  unsigned int iso=RefinementCase<dim>::isotropic_refinement-1;
-  switch (dim)
-    {
-      case 2:   // 2d
-      {
-       switch (degree)
-         {
-           case 1:
-           {
-                                               // this is a strange
-                                               // element, since it is
-                                               // both additive and
-                                               // then it is also
-                                               // not. ideally, we
-                                               // would like to have
-                                               // the value of the
-                                               // shape function on
-                                               // the coarse line to
-                                               // be the mean value of
-                                               // that on the two
-                                               // child ones. thus,
-                                               // one should make it
-                                               // additive. however,
-                                               // additivity only
-                                               // works if an element
-                                               // does not have any
-                                               // continuity
-                                               // requirements, since
-                                               // otherwise degrees of
-                                               // freedom are shared
-                                               // between adjacent
-                                               // elements, and when
-                                               // we make the element
-                                               // additive, that would
-                                               // mean that we end up
-                                               // adding up
-                                               // contributions not
-                                               // only from the child
-                                               // cells of this cell,
-                                               // but also from the
-                                               // child cells of the
-                                               // neighbor, and since
-                                               // we cannot know
-                                               // whether there even
-                                               // exists a neighbor we
-                                               // cannot simply make
-                                               // the element
-                                               // additive.
-                                              //
-                                               // so, until someone
-                                               // comes along with a
-                                               // better alternative,
-                                               // we do the following:
-                                               // make the element
-                                               // non-additive, and
-                                               // simply pick the
-                                               // value of one of the
-                                               // child lines for the
-                                               // value of the mother
-                                               // line (note that we
-                                               // have to multiply by
-                                               // two, since the shape
-                                               // functions scale with
-                                               // the inverse
-                                               // Jacobian). we thus
-                                               // throw away the
-                                               // information of one
-                                               // of the child lines,
-                                               // but there seems to
-                                               // be no other way than
-                                               // that...
-                                               //
-                                               // note: to make things
-                                               // consistent, and
-                                               // restriction
-                                               // independent of the
-                                               // order in which we
-                                               // travel across the
-                                               // cells of the coarse
-                                               // grid, we have to
-                                               // make sure that we
-                                               // take the same small
-                                               // line when visiting
-                                               // its two neighbors,
-                                               // to get the value for
-                                               // the mother line. we
-                                               // take the first line
-                                               // always, in the
-                                               // canonical direction
-                                               // of lines
-              for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_cell; ++c)
-                this->restriction[iso][c].reinit (this->dofs_per_cell,
-                                                 this->dofs_per_cell);
-             
-             this->restriction[iso][0](0,0) = 2.;
-             this->restriction[iso][1](1,1) = 2.;
-             this->restriction[iso][0](2,2) = 2.;
-             this->restriction[iso][2](3,3) = 2.;
-
-             break;
-           };
-           
-           default:
-           {
-                                              // in case we don't
-                                              // have the matrices
-                                              // (yet), leave them
-                                              // empty. this does not
-                                              // prevent the use of
-                                              // this FE, but will
-                                              // prevent the use of
-                                              // these matrices
-              break;
-           };
-         };
-       
-       break;
-      };
-
-
-      case 3:   // 3d
-      {
-       switch (degree)
-         {
-           case 1:
-           {
-                                              // same principle as in
-                                              // 2d, take one child
-                                              // cell to get at the
-                                              // values of each of
-                                              // the 12 lines
-              for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_cell; ++c)
-                this->restriction[iso][c].reinit (this->dofs_per_cell,
-                                                 this->dofs_per_cell);
-             this->restriction[iso][0](0,0) = 2.;
-             this->restriction[iso][1](1,1) = 2.;
-             this->restriction[iso][0](2,2) = 2.;
-             this->restriction[iso][2](3,3) = 2.;
-              
-             this->restriction[iso][4](4,4) = 2.;
-             this->restriction[iso][5](5,5) = 2.;
-             this->restriction[iso][4](6,6) = 2.;
-             this->restriction[iso][6](7,7) = 2.;
-              
-             this->restriction[iso][0](8,8) = 2.;
-             this->restriction[iso][1](9,9) = 2.;
-             this->restriction[iso][2](10,10) = 2.;
-             this->restriction[iso][3](11,11) = 2.;
-              
-             break;
-           };
-           
-           default:
-           {
-                                              // in case we don't
-                                              // have the matrices
-                                              // (yet), leave them
-                                              // empty. this does not
-                                              // prevent the use of
-                                              // this FE, but will
-                                              // prevent the use of
-                                              // these matrices
-              break;
-           };
-         };
-       
-       break;
-      };
-      
       default:
-           Assert (false,ExcNotImplemented());
+        {
+          Assert (false, ExcNotImplemented ());
+          return false;
+        }
     }
 }
 
-
-
-template <int dim, int spacedim>
-void FE_Nedelec<dim,spacedim>::initialize_unit_support_points ()
+template <int dim>
+bool
+FE_Nedelec<dim>::hp_constraints_are_implemented () const
 {
-  switch (degree)
-    {
-      case 1:
-      {
-                                        // all degrees of freedom are
-                                        // on edges, and their order
-                                        // is the same as the edges
-                                        // themselves
-       this->unit_support_points.resize(GeometryInfo<dim>::lines_per_cell);
-       for (unsigned int line=0; line<GeometryInfo<dim>::lines_per_cell; ++line)
-         {
-           const unsigned int
-             vertex_index_0 = GeometryInfo<dim>::line_to_cell_vertices(line,0),
-             vertex_index_1 = GeometryInfo<dim>::line_to_cell_vertices(line,1);
-           
-           const Point<dim>
-             vertex_0 = GeometryInfo<dim>::unit_cell_vertex(vertex_index_0),
-             vertex_1 = GeometryInfo<dim>::unit_cell_vertex(vertex_index_1);
-           
-                                            // place dofs right
-                                            // between the vertices
-                                            // of each line
-           this->unit_support_points[line] = (vertex_0 + vertex_1) / 2;
-         };
-           
-       break;
-      };
-
-      default:
-                                            // no higher order
-                                            // elements implemented
-                                            // right now
-           Assert (false, ExcNotImplemented());
-    };
+  return true;
 }
 
-
-#if deal_II_dimension == 1
-
-template <>
-void FE_Nedelec<1>::initialize_unit_face_support_points ()
+template <int dim>
+std::vector<std::pair<unsigned int, unsigned int> >
+FE_Nedelec<dim>::hp_vertex_dof_identities (const FiniteElement<dim>& fe_other)
+const
 {
-                                  // no faces in 1d, so nothing to do
+                   // Nedelec elements do not have any dofs
+                   // on vertices, hence return an empty vector.
+  return std::vector<std::pair<unsigned int, unsigned int> > ();
 }
 
-#endif
-
-
-template <int dim, int spacedim>
-void FE_Nedelec<dim,spacedim>::initialize_unit_face_support_points ()
+template <int dim>
+std::vector<std::pair<unsigned int, unsigned int> >
+FE_Nedelec<dim>::hp_line_dof_identities (const FiniteElement<dim>& fe_other)
+const
 {
-  switch (degree)
+                                  // we can presently only compute these
+                                  // identities if both FEs are
+                                  // FE_Nedelec or if the other one is an
+                                  // FE_Nothing
+  if (const FE_Nedelec<dim> *fe_nedelec_other
+        = dynamic_cast<const FE_Nedelec<dim>*> (&fe_other))
     {
-      case 1:
-      {
-                                        // do this the same as above, but
-                                        // for one dimension less
-       this->unit_face_support_points.resize(GeometryInfo<dim-1>::lines_per_cell);
-       for (unsigned int line=0; line<GeometryInfo<dim-1>::lines_per_cell; ++line)
-         {
-           const unsigned int
-             vertex_index_0 = GeometryInfo<dim-1>::line_to_cell_vertices(line,0),
-             vertex_index_1 = GeometryInfo<dim-1>::line_to_cell_vertices(line,1);
-      
-           const Point<dim-1>
-             vertex_0 = GeometryInfo<dim-1>::unit_cell_vertex(vertex_index_0),
-             vertex_1 = GeometryInfo<dim-1>::unit_cell_vertex(vertex_index_1);
-
-                                            // place dofs right
-                                            // between the vertices of each
-                                            // line
-             this->unit_face_support_points[line] = (vertex_0 + vertex_1) / 2;
-         };
-       break;
-      };
-
-      default:
-                                            // no higher order
-                                            // elements implemented
-                                            // right now
-           Assert (false, ExcNotImplemented());
-    };     
-}
+                                      // dofs are located on lines, so
+                                      // two dofs are identical, if their
+                                      // edge shape functions have the
+                                      // same polynomial degree.
+      std::vector<std::pair<unsigned int, unsigned int> > identities;
 
+      for (unsigned int i = 0;
+           i < std::min (fe_nedelec_other->degree, this->degree); ++i)
+        identities.push_back (std::make_pair (i, i));
 
+      return identities;
+    }
 
-template <int dim, int spacedim>
-std::vector<unsigned int>
-FE_Nedelec<dim,spacedim>::get_dpo_vector(const unsigned int degree)
-{
-  Assert (degree == 1, ExcNotImplemented());
-
-                                  // for degree==1, put all degrees
-                                  // of freedom on the lines, and in
-                                  // particular @p{degree} DoFs per
-                                  // line:
-  std::vector<unsigned int> dpo(dim+1, 0U);
-  dpo[1] = degree;
-
-  return dpo;
+  else
+    if (dynamic_cast<const FE_Nothing<dim>*> (&fe_other) != 0)
+      {
+                                      // the FE_Nothing has no
+                                      // degrees of freedom, so there
+                                      // are no equivalencies to be
+                                      // recorded
+        return std::vector<std::pair<unsigned int, unsigned int> > ();
+      }
+
+    else
+      {
+        Assert (false, ExcNotImplemented ());
+        return std::vector<std::pair<unsigned int, unsigned int> > ();
+      }
 }
 
-
-
-template <int dim, int spacedim>
-UpdateFlags
-FE_Nedelec<dim,spacedim>::update_once (const UpdateFlags) const
+template <int dim>
+std::vector<std::pair<unsigned int, unsigned int> >
+FE_Nedelec<dim>::hp_quad_dof_identities (const FiniteElement<dim>& fe_other)
+const
 {
-                                  // even the values have to be
-                                  // computed on the real cell, so
-                                  // nothing can be done in advance
-  return update_default;
-}
-
-
-
-template <int dim, int spacedim>
-UpdateFlags
-FE_Nedelec<dim,spacedim>::update_each (const UpdateFlags flags) const
-{
-  UpdateFlags out = update_default;
+                                  // we can presently only compute
+                                  // these identities if both FEs are
+                                  // FE_Nedelec or if the other one is an
+                                  // FE_Nothing
+  if (const FE_Nedelec<dim> *fe_nedelec_other
+        = dynamic_cast<const FE_Nedelec<dim>*> (&fe_other))
+    {
+                                      // dofs are located on the interior
+                                      // of faces, so two dofs are identical,
+                                      // if their face shape functions have
+                                      // the same polynomial degree.
+      const unsigned int p = fe_nedelec_other->degree;
+      const unsigned int q = this->degree;
+      const unsigned int p_min = std::min (p, q);
+      std::vector<std::pair<unsigned int, unsigned int> > identities;
+
+      for (unsigned int i = 0; i < p_min; ++i)
+        for (unsigned int j = 0; j < p_min - 1; ++j)
+          {
+            identities.push_back (std::make_pair ((i + 1) * (q + 1) + j,
+                                                  (i + 1) * (p + 1) + j));
+            identities.push_back (std::make_pair (i + (j + q + 2) * q,
+                                                  i + (j + p + 2) * p));
+          }
 
-  if (flags & update_values)
-    out |= update_values             | update_covariant_transformation;
-  if (flags & update_gradients)
-    out |= update_gradients          | update_covariant_transformation;
-  if (flags & update_hessians)
-    out |= update_hessians | update_covariant_transformation;
+      return identities;
+    }
 
-  return out;
+  else
+    if (dynamic_cast<const FE_Nothing<dim>*> (&fe_other) != 0)
+      {
+                                      // the FE_Nothing has no
+                                      // degrees of freedom, so there
+                                      // are no equivalencies to be
+                                      // recorded
+        return std::vector<std::pair<unsigned int, unsigned int> > ();
+      }
+
+    else
+      {
+        Assert (false, ExcNotImplemented ());
+        return std::vector<std::pair<unsigned int, unsigned int> > ();
+      }
 }
 
-
-
-//---------------------------------------------------------------------------
-// Data field initialization
-//---------------------------------------------------------------------------
-
-template <int dim, int spacedim>
-typename Mapping<dim,spacedim>::InternalDataBase *
-FE_Nedelec<dim,spacedim>::get_data (const UpdateFlags      update_flags,
-                          const Mapping<dim,spacedim>    &mapping,
-                          const Quadrature<dim> &quadrature) const
+                   // In this function we compute the face
+                   // interpolation matrix. This is usually
+                   // done by projection-based interpolation,
+                   // but, since one can compute the entries
+                   // easy per hand, we save some computation
+                   // time at this point and just fill in the
+                   // correct values.
+template <int dim>
+void
+FE_Nedelec<dim>::get_face_interpolation_matrix
+  (const FiniteElement<dim>& source, FullMatrix<double>& interpolation_matrix)
+const
 {
-                                  // generate a new data object and
-                                  // initialize some fields
-   InternalData* data = new InternalData;
-
-                                  // check what needs to be
-                                  // initialized only once and what
-                                  // on every cell/face/subface we
-                                  // visit
-   data->update_once = update_once(update_flags);
-   data->update_each = update_each(update_flags);
-   data->update_flags = data->update_once | data->update_each;
-
-   const UpdateFlags flags(data->update_flags);
-   const unsigned int n_q_points = quadrature.size();
-
-                                  // initialize fields only if really
-                                  // necessary. otherwise, don't
-                                  // allocate memory
-   if (flags & update_values)
-     data->shape_values.resize (this->dofs_per_cell,
-                                std::vector<Tensor<1,dim> > (n_q_points));
-
-   if (flags & update_gradients)
-     data->shape_gradients.resize (this->dofs_per_cell,
-                                   std::vector<Tensor<2,dim> > (n_q_points));
-
-                                  // if second derivatives through
-                                  // finite differencing is required,
-                                  // then initialize some objects for
-                                  // that
-   if (flags & update_hessians)
-     data->initialize_2nd (this, mapping, quadrature);
-
-                                  // next already fill those fields
-                                  // of which we have information by
-                                  // now. note that the shape values
-                                  // and gradients are only those on
-                                  // the unit cell, and need to be
-                                  // transformed when visiting an
-                                  // actual cell
-   for (unsigned int i=0; i<this->dofs_per_cell; ++i)
-     for (unsigned int q=0; q<n_q_points; ++q)
-       {
-        if (flags & update_values)
-          for (unsigned int c=0; c<dim; ++c)
-            data->shape_values[i][q][c]
-              = shape_value_component(i,quadrature.point(q),c);
-       
-        if (flags & update_gradients)
-          for (unsigned int c=0; c<dim; ++c)
-            data->shape_gradients[i][q][c]
-              = shape_grad_component(i,quadrature.point(q),c);
-       }
-   
-   return data;
+                                  // this is only implemented, if the
+                                  // source FE is also a
+                                  // Nedelec element
+  typedef FE_Nedelec<dim> FEN;
+  typedef FiniteElement<dim> FEL;
+
+  AssertThrow ((source.get_name ().find ("FE_Nedelec<") == 0) ||
+               (dynamic_cast<const FEN*> (&source) != 0),
+                typename FEL::ExcInterpolationNotImplemented());
+  Assert (interpolation_matrix.m () == source.dofs_per_face,
+          ExcDimensionMismatch (interpolation_matrix.m (),
+                                source.dofs_per_face));
+  Assert (interpolation_matrix.n () == this->dofs_per_face,
+          ExcDimensionMismatch (interpolation_matrix.n (),
+                                this->dofs_per_face));
+
+                                  // ok, source is a Nedelec element, so
+                                  // we will be able to do the work
+  const FE_Nedelec<dim> &source_fe
+    = dynamic_cast<const FE_Nedelec<dim>&> (source);
+
+                                  // Make sure, that the element,
+                   // for which the DoFs should be
+                   // constrained is the one with
+                   // the higher polynomial degree.
+                   // Actually the procedure will work
+                   // also if this assertion is not
+                   // satisfied. But the matrices
+                   // produced in that case might
+                                  // lead to problems in the
+                   // hp procedures, which use this
+                                  // method.
+  Assert (this->dofs_per_face <= source_fe.dofs_per_face,
+          typename FEL::ExcInterpolationNotImplemented ());
+  interpolation_matrix = 0;
+
+                   // On lines we can just identify
+                   // all degrees of freedom.
+  for (unsigned int i = 0; i <= deg; ++i)
+    interpolation_matrix (i, i) = 1.0;
+
+                   // In 3d we have some lines more
+                   // and a face. The procedure stays
+                   // the same as above, but we have
+                   // to take a bit more care of the
+                   // indices of the degrees of
+                   // freedom.
+  if (dim == 3)
+    for (unsigned int i = 0; i <= deg; ++i)
+      {
+        for (unsigned int j = 1; j < GeometryInfo<dim>::lines_per_face; ++j)
+          interpolation_matrix (j * source_fe.degree + i,
+                                j * this->degree + i) = 1.0;
+         
+        for (unsigned int j = 0; j < deg; ++j)
+          {
+            interpolation_matrix
+              (i + (j + GeometryInfo<2>::lines_per_cell) * source_fe.degree,
+               i + (j + GeometryInfo<2>::lines_per_cell) * this->degree)
+              = 1.0;
+            interpolation_matrix
+              ((i * (source_fe.degree - 1)
+               + GeometryInfo<2>::lines_per_cell) * source_fe.degree + j,
+               (i * deg + GeometryInfo<2>::lines_per_cell) * this->degree)
+              = 1.0;
+          }
+      }
 }
 
+#if deal_II_dimension == 1
 
-
-
-//---------------------------------------------------------------------------
-// Fill data of FEValues
-//---------------------------------------------------------------------------
-
-template <int dim, int spacedim>
+template <int dim>
 void
-FE_Nedelec<dim,spacedim>::fill_fe_values 
-  (const Mapping<dim,spacedim>                      &mapping,
-   const typename Triangulation<dim,spacedim>::cell_iterator &cell,
-   const Quadrature<dim>                            &quadrature,
-   typename Mapping<dim,spacedim>::InternalDataBase &mapping_data,
-   typename Mapping<dim,spacedim>::InternalDataBase &fedata,
-   FEValuesData<dim,spacedim>                       &data,
-   CellSimilarity::Similarity                  &/*cell_similarity*/) const
+FE_Nedelec<dim>::get_subface_interpolation_matrix
+  (const FiniteElement<dim>& source, const unsigned int subface,
+   FullMatrix<double>& interpolation_matrix) const
 {
-                                  // convert data object to internal
-                                  // data for this class. fails with
-                                  // an exception if that is not
-                                  // possible
-  Assert (dynamic_cast<InternalData *> (&fedata) != 0,
-         ExcInternalError());
-  InternalData &fe_data = static_cast<InternalData &> (fedata);
-
-                                  // get the flags indicating the
-                                  // fields that have to be filled
-  const UpdateFlags flags(fe_data.current_update_flags());
-
-  const unsigned int n_q_points = quadrature.size();
-                                 
-                                  // fill shape function
-                                  // values. these are vector-valued,
-                                  // so we have to transform
-                                  // them. since the output format
-                                  // (in data.shape_values) is a
-                                  // sequence of doubles (one for
-                                  // each non-zero shape function
-                                  // value, and for each quadrature
-                                  // point, rather than a sequence of
-                                  // small vectors, we have to use a
-                                  // number of conversions
-  if (flags & update_values)
-    {
-      std::vector<Tensor<1,dim> > shape_values (n_q_points);
-
-      Assert (data.shape_values.n_rows() == this->dofs_per_cell * dim,
-             ExcInternalError());
-      Assert (data.shape_values.n_cols() == n_q_points,
-             ExcInternalError());
-      
-      for (unsigned int k=0; k<this->dofs_per_cell; ++k)
-       {
-                                          // first transform shape
-                                          // values...
-         Assert (fe_data.shape_values[k].size() == n_q_points,
-                 ExcInternalError());
-         mapping.transform(fe_data.shape_values[k], shape_values,
-                           mapping_data, mapping_covariant);
-
-                                          // then copy over to target:
-         for (unsigned int q=0; q<n_q_points; ++q)
-           for (unsigned int d=0; d<dim; ++d)
-             data.shape_values[k*dim+d][q] = shape_values[q][d];
-       };
-    };
-  
-      
-  if (flags & update_gradients)
-    {
-      std::vector<Tensor<2,dim> > shape_grads1 (n_q_points);
-      std::vector<Tensor<2,dim> > shape_grads2 (n_q_points);
-
-      Assert (data.shape_gradients.size() == this->dofs_per_cell * dim,
-             ExcInternalError());
-      Assert (data.shape_gradients[0].size() == n_q_points,
-             ExcInternalError());
-
-                                       // loop over all shape
-                                       // functions, and treat the
-                                       // gradients of each shape
-                                       // function at all quadrature
-                                       // points
-      for (unsigned int k=0; k<this->dofs_per_cell; ++k)
-       {
-                                           // treat the gradients of
-                                           // this particular shape
-                                           // function at all
-                                           // q-points. if Dv is the
-                                           // gradient of the shape
-                                           // function on the unit
-                                           // cell, then
-                                           // (J^-T)Dv(J^-1) is the
-                                           // value we want to have on
-                                           // the real cell. so, we
-                                           // will have to apply a
-                                           // covariant transformation
-                                           // to Dv twice. since the
-                                           // interface only allows
-                                           // multiplication with
-                                           // (J^-1) from the right,
-                                           // we have to trick a
-                                           // little in between
-         Assert (fe_data.shape_gradients[k].size() == n_q_points,
-                 ExcInternalError());
-                                           // do first transformation
-         mapping.transform(fe_data.shape_gradients[k], shape_grads1,
-                           mapping_data, mapping_covariant);
-                                           // transpose matrix
-          for (unsigned int q=0; q<n_q_points; ++q)
-            shape_grads2[q] = transpose(shape_grads1[q]);
-                                           // do second transformation
-         mapping.transform(shape_grads2, shape_grads1,
-                           mapping_data, mapping_covariant);
-                                           // transpose back
-          for (unsigned int q=0; q<n_q_points; ++q)
-            shape_grads2[q] = transpose(shape_grads1[q]);
-          
-                                          // then copy over to target:
-         for (unsigned int q=0; q<n_q_points; ++q)
-           for (unsigned int d=0; d<dim; ++d)
-             data.shape_gradients[k*dim+d][q] = shape_grads2[q][d];
-       };
-    }
-
-  if (flags & update_hessians)
-    this->compute_2nd (mapping, cell,
-                       QProjector<dim>::DataSetDescriptor::cell(),
-                       mapping_data, fe_data, data);
+  Assert (false, ExcNotImplemented ());
 }
 
-
-
-template <int dim, int spacedim>
+#else
+
+                   // In this function we compute the
+                   // subface interpolation matrix.
+                   // This is done by a projection-
+                   // based interpolation. Therefore
+                   // we first interpolate the
+                   // shape functions of the higher
+                   // order element on the lowest
+                   // order edge shape functions.
+                   // Then the remaining part of
+                   // the interpolated shape
+                   // functions is projected on the
+                   // higher order edge shape
+                   // functions, the face shape
+                   // functions and the interior
+                   // shape functions (if they all
+                   // exist).
+template <int dim>
 void
-FE_Nedelec<dim,spacedim>::fill_fe_face_values (const Mapping<dim,spacedim>                   &mapping,
-                                     const typename Triangulation<dim,spacedim>::cell_iterator &cell,
-                                     const unsigned int                    face,
-                                     const Quadrature<dim-1>              &quadrature,
-                                     typename Mapping<dim,spacedim>::InternalDataBase       &mapping_data,
-                                     typename Mapping<dim,spacedim>::InternalDataBase       &fedata,
-                                     FEValuesData<dim,spacedim>                    &data) const
+FE_Nedelec<dim>::get_subface_interpolation_matrix
+  (const FiniteElement<dim>& source, const unsigned int subface,
+   FullMatrix<double>& interpolation_matrix) const
 {
-                                  // convert data object to internal
-                                  // data for this class. fails with
-                                  // an exception if that is not
-                                  // possible
-  InternalData &fe_data = dynamic_cast<InternalData &> (fedata);
-
-                                   // offset determines which data set
-                                  // to take (all data sets for all
-                                  // faces are stored contiguously)
-  const typename QProjector<dim>::DataSetDescriptor offset
-    = (QProjector<dim>::DataSetDescriptor::
-       face (face,
-            cell->face_orientation(face),
-            cell->face_flip(face),
-            cell->face_rotation(face),
-             quadrature.size()));
-
-                                  // get the flags indicating the
-                                  // fields that have to be filled
-  const UpdateFlags flags(fe_data.current_update_flags());
-
-  const unsigned int n_q_points = quadrature.size();
-                                 
-                                  // fill shape function
-                                  // values. these are vector-valued,
-                                  // so we have to transform
-                                  // them. since the output format
-                                  // (in data.shape_values) is a
-                                  // sequence of doubles (one for
-                                  // each non-zero shape function
-                                  // value, and for each quadrature
-                                  // point, rather than a sequence of
-                                  // small vectors, we have to use a
-                                  // number of conversions
-  if (flags & update_values)
-    {
-                                       // check size of array. in 3d,
-                                       // we have faces oriented both
-                                       // ways
-      Assert (fe_data.shape_values[0].size() ==
-              GeometryInfo<dim>::faces_per_cell * n_q_points *
-              (dim == 3 ? 8 : 1),
-              ExcInternalError());
-      
-      std::vector<Tensor<1,dim> > shape_values (n_q_points);
-
-      Assert (data.shape_values.n_rows() == this->dofs_per_cell * dim,
-             ExcInternalError());
-      Assert (data.shape_values.n_cols() == n_q_points,
-             ExcInternalError());
-      
-      for (unsigned int k=0; k<this->dofs_per_cell; ++k)
-       {
-                                          // first transform shape
-                                          // values...
-         mapping.transform(make_slice(fe_data.shape_values[k], offset, n_q_points),
-                           shape_values, mapping_data, mapping_covariant);
-
-                                          // then copy over to target:
-         for (unsigned int q=0; q<n_q_points; ++q)
-           for (unsigned int d=0; d<dim; ++d)
-             data.shape_values[k*dim+d][q] = shape_values[q][d];
-       };
-    };
-  
-      
-  if (flags & update_gradients)
+                                  // this is only implemented, if the
+                                  // source FE is also a
+                                  // Nedelec element
+  typedef FE_Nedelec<dim> FEN;
+  typedef FiniteElement<dim> FEL;
+
+  AssertThrow ((source.get_name ().find ("FE_Nedelec<") == 0) ||
+               (dynamic_cast<const FEN*> (&source) != 0),
+                typename FEL::ExcInterpolationNotImplemented ());
+  Assert (interpolation_matrix.m () == source.dofs_per_face,
+          ExcDimensionMismatch (interpolation_matrix.m (),
+                                source.dofs_per_face));
+  Assert (interpolation_matrix.n () == this->dofs_per_face,
+          ExcDimensionMismatch (interpolation_matrix.n (),
+                                this->dofs_per_face));
+
+                                  // ok, source is a Nedelec element, so
+                                  // we will be able to do the work
+  const FE_Nedelec<dim> &source_fe
+    = dynamic_cast<const FE_Nedelec<dim>&> (source);
+
+                                  // Make sure, that the element,
+                   // for which the DoFs should be
+                   // constrained is the one with
+                   // the higher polynomial degree.
+                   // Actually the procedure will work
+                   // also if this assertion is not
+                   // satisfied. But the matrices
+                   // produced in that case might
+                                  // lead to problems in the
+                   // hp procedures, which use this
+                                  // method.
+  Assert (this->dofs_per_face <= source_fe.dofs_per_face,
+          typename FEL::ExcInterpolationNotImplemented ());
+  interpolation_matrix = 0;
+                          // Perform projection-based interpolation
+                                  // as usual.
+  switch (dim)
     {
-                                       // check size of array. in 3d,
-                                       // we have faces oriented both
-                                       // ways
-      Assert (fe_data.shape_gradients[0].size() ==
-              GeometryInfo<dim>::faces_per_cell * n_q_points *
-              (dim == 3 ? 8 : 1),
-              ExcInternalError());
-
-      std::vector<Tensor<2,dim> > shape_grads1 (n_q_points);
-      std::vector<Tensor<2,dim> > shape_grads2 (n_q_points);
-
-      Assert (data.shape_gradients.size() == this->dofs_per_cell * dim,
-             ExcInternalError());
-      Assert (data.shape_gradients[0].size() == n_q_points,
-             ExcInternalError());
-
-                                       // loop over all shape
-                                       // functions, and treat the
-                                       // gradients of each shape
-                                       // function at all quadrature
-                                       // points
-      for (unsigned int k=0; k<this->dofs_per_cell; ++k)
-       {
-                                           // treat the gradients of
-                                           // this particular shape
-                                           // function at all
-                                           // q-points. if Dv is the
-                                           // gradient of the shape
-                                           // function on the unit
-                                           // cell, then
-                                           // (J^-T)Dv(J^-1) is the
-                                           // value we want to have on
-                                           // the real cell. so, we
-                                           // will have to apply a
-                                           // covariant transformation
-                                           // to Dv twice. since the
-                                           // interface only allows
-                                           // multiplication with
-                                           // (J^-1) from the right,
-                                           // we have to trick a
-                                           // little in between
-                                           // 
-                                           // do first transformation
-         mapping.transform(make_slice(fe_data.shape_gradients[k], offset, n_q_points),
-                           shape_grads1, mapping_data, mapping_covariant);
-                                           // transpose matrix
-          for (unsigned int q=0; q<n_q_points; ++q)
-            shape_grads2[q] = transpose(shape_grads1[q]);
-                                           // do second transformation
-         mapping.transform(shape_grads2, shape_grads1,
-                           mapping_data, mapping_covariant);
-                                           // transpose back
-          for (unsigned int q=0; q<n_q_points; ++q)
-            shape_grads2[q] = transpose(shape_grads1[q]);
-          
-                                          // then copy over to target:
-         for (unsigned int q=0; q<n_q_points; ++q)
-           for (unsigned int d=0; d<dim; ++d)
-             data.shape_gradients[k*dim+d][q] = shape_grads2[q][d];
-       };
-    }
+      case 2:
+        {
+          const QGauss<dim - 1> reference_edge_quadrature (this->degree);
+          const Quadrature<dim - 1>& edge_quadrature
+            = QProjector<dim - 1>::project_to_child
+              (reference_edge_quadrature, subface);
+          const unsigned int& n_edge_points = edge_quadrature.size ();
+          const std::vector<Point<dim - 1> >&
+            quadrature_points = edge_quadrature.get_points ();
+
+                                  // Let us begin with the
+                                  // interpolation part.
+          for (unsigned int q_point = 0; q_point < n_edge_points; ++q_point)
+            {
+              const double weight = 2.0 * edge_quadrature.weight (q_point);
+
+              for (unsigned int dof = 0; dof < this->dofs_per_face; ++dof)
+                interpolation_matrix (0, dof)
+                  += weight
+                     * this->shape_value_component
+                       (dof, Point<dim> (0.0, quadrature_points[q_point] (0)),
+                        1);
+            }
+         
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+          for (unsigned int dof = 0; dof < this->dofs_per_face; ++dof)
+            if (std::abs (interpolation_matrix (0, dof)) < 1e-14)
+              interpolation_matrix (0, dof) = 0.0;
+
+                                  // If the degree is greater
+                                  // than 0, then we have still
+                                  // some higher order edge
+                                  // shape functions to
+                                  // consider.
+                                  // Here the projection part
+                                  // starts. The dof values
+                                  // are obtained by solving
+                                  // a linear system of
+                                  // equations.
+          if (deg > 0)
+            {
+                                 // Shift value for scaling
+                                 // of quadrature points.
+              const double shift[2] = {0.0, -1.0};
+              const std::vector<Polynomials::Polynomial<double> >&
+                lobatto_polynomials
+                  = Polynomials::Lobatto::generate_complete_basis
+                    (this->degree);
+              FullMatrix<double> assembling_matrix (deg, n_edge_points);
+              std::vector<Polynomials::Polynomial<double> >
+                lobatto_polynomials_grad (this->degree);
+
+              for (unsigned int i = 0; i < lobatto_polynomials_grad.size ();
+                   ++i)
+                lobatto_polynomials_grad[i]
+                  = lobatto_polynomials[i + 1].derivative ();
+
+                                  // Set up the system matrix
+                                  // and right hand side
+                                  // vector.
+              for (unsigned int q_point = 0; q_point < n_edge_points;
+                   ++q_point)
+                {
+                         const double tmp = 2.0 * quadrature_points[q_point] (0)
+                                            + shift[subface];
+                         const double weight
+                           = std::sqrt (2.0 * edge_quadrature.weight (q_point));
+
+                  for (unsigned int i = 0; i < deg; ++i)
+                    assembling_matrix (i, q_point)
+                      = weight * lobatto_polynomials_grad[i + 1].value (tmp);
+                       }
+                         
+              FullMatrix<double> system_matrix (deg, deg);
+              
+              assembling_matrix.mTmult (system_matrix, assembling_matrix);
+              
+              FullMatrix<double> system_matrix_inv (deg, deg);
+              
+              system_matrix_inv.invert (system_matrix);
+                  
+              Vector<double> solution (deg);
+              Vector<double> system_rhs (deg);
+              
+              for (unsigned int dof = 0; dof < this->dofs_per_face; ++dof)
+                {
+                  system_rhs = 0;
+                  
+                  for (unsigned int q_point = 0; q_point < n_edge_points;
+                       ++q_point)
+                    {
+                      const double tmp
+                        = 2.0 * quadrature_points[q_point] (0)
+                          + shift[subface];
+                      const double weight
+                        = 2.0 * edge_quadrature.weight (q_point)
+                          * (this->shape_value_component
+                             (dof, Point<dim> (0.0,
+                                               quadrature_points[q_point] (0)),
+                              1) - interpolation_matrix (0, dof));
+                        
+                      for (unsigned int i = 0;  i < deg; ++i)
+                        system_rhs (i)
+                          += weight
+                             * lobatto_polynomials_grad[i + 1].value (tmp);
+                    }
 
-  if (flags & update_hessians)
-    this->compute_2nd (mapping, cell, offset, mapping_data, fe_data, data);
-}
+                  system_matrix_inv.vmult (solution, system_rhs);
 
+                  for (unsigned int i = 0; i < deg; ++i)
+                    if (std::abs (solution (i)) > 1e-14)
+                      interpolation_matrix (i + 1, dof) = solution (i);
+                }
+            }
 
+          break;
+        }
 
-template <int dim, int spacedim>
-void
-FE_Nedelec<dim,spacedim>::fill_fe_subface_values (const Mapping<dim,spacedim>                   &mapping,
-                                        const typename Triangulation<dim,spacedim>::cell_iterator &cell,
-                                        const unsigned int                    face,
-                                        const unsigned int                    subface,
-                                        const Quadrature<dim-1>              &quadrature,
-                                        typename Mapping<dim,spacedim>::InternalDataBase       &mapping_data,
-                                        typename Mapping<dim,spacedim>::InternalDataBase       &fedata,
-                                        FEValuesData<dim,spacedim>                    &data) const
-{
-                                  // convert data object to internal
-                                  // data for this class. fails with
-                                  // an exception if that is not
-                                  // possible
-  InternalData &fe_data = dynamic_cast<InternalData &> (fedata);
-
-                                   // offset determines which data set
-                                  // to take (all data sets for all
-                                  // faces are stored contiguously)
-  const typename QProjector<dim>::DataSetDescriptor offset
-    = (QProjector<dim>::DataSetDescriptor::
-       subface (face, subface,
-               cell->face_orientation(face),
-               cell->face_flip(face),
-               cell->face_rotation(face),
-               quadrature.size(),
-               cell->subface_case(face)));
-
-                                  // get the flags indicating the
-                                  // fields that have to be filled
-  const UpdateFlags flags(fe_data.current_update_flags());
-
-  const unsigned int n_q_points = quadrature.size();
-                                 
-                                  // fill shape function
-                                  // values. these are vector-valued,
-                                  // so we have to transform
-                                  // them. since the output format
-                                  // (in data.shape_values) is a
-                                  // sequence of doubles (one for
-                                  // each non-zero shape function
-                                  // value, and for each quadrature
-                                  // point, rather than a sequence of
-                                  // small vectors, we have to use a
-                                  // number of conversions
-  if (flags & update_values)
-    {
-      Assert (fe_data.shape_values[0].size() ==
-             GeometryInfo<dim>::max_children_per_face *
-              GeometryInfo<dim>::faces_per_cell *
-             n_q_points,
-             ExcInternalError());
-      
-      std::vector<Tensor<1,dim> > shape_values (n_q_points);
+      case 3:
+        {
+          const QGauss<dim - 2> reference_edge_quadrature (this->degree);
 
-      Assert (data.shape_values.n_rows() == this->dofs_per_cell * dim,
-             ExcInternalError());
-      Assert (data.shape_values.n_cols() == n_q_points,
-             ExcInternalError());
-      
-      for (unsigned int k=0; k<this->dofs_per_cell; ++k)
-       {
-                                          // first transform shape
-                                          // values...
-         mapping.transform(make_slice(fe_data.shape_values[k], offset, n_q_points),
-                           shape_values, mapping_data, mapping_covariant);
-
-                                          // then copy over to target:
-         for (unsigned int q=0; q<n_q_points; ++q)
-           for (unsigned int d=0; d<dim; ++d)
-             data.shape_values[k*dim+d][q] = shape_values[q][d];
-       };
-    };
-  
-      
-  if (flags & update_gradients)
-    {
-      Assert (fe_data.shape_gradients.size() ==
-              GeometryInfo<dim>::faces_per_cell *
-             GeometryInfo<dim>::max_children_per_face *
-             n_q_points,
-              ExcInternalError());
-
-      std::vector<Tensor<2,dim> > shape_grads1 (n_q_points);
-      std::vector<Tensor<2,dim> > shape_grads2 (n_q_points);
-
-      Assert (data.shape_gradients.size() == this->dofs_per_cell * dim,
-             ExcInternalError());
-      Assert (data.shape_gradients[0].size() == n_q_points,
-             ExcInternalError());
-
-                                       // loop over all shape
-                                       // functions, and treat the
-                                       // gradients of each shape
-                                       // function at all quadrature
-                                       // points
-      for (unsigned int k=0; k<this->dofs_per_cell; ++k)
-       {
-                                           // treat the gradients of
-                                           // this particular shape
-                                           // function at all
-                                           // q-points. if Dv is the
-                                           // gradient of the shape
-                                           // function on the unit
-                                           // cell, then
-                                           // (J^-T)Dv(J^-1) is the
-                                           // value we want to have on
-                                           // the real cell. so, we
-                                           // will have to apply a
-                                           // covariant transformation
-                                           // to Dv twice. since the
-                                           // interface only allows
-                                           // multiplication with
-                                           // (J^-1) from the right,
-                                           // we have to trick a
-                                           // little in between
-                                           // 
-                                           // do first transformation
-         mapping.transform(make_slice(fe_data.shape_gradients[k], offset, n_q_points),
-                           shape_grads1, mapping_data, mapping_covariant);
-                                           // transpose matrix
-          for (unsigned int q=0; q<n_q_points; ++q)
-            shape_grads2[q] = transpose(shape_grads1[q]);
-                                           // do second transformation
-         mapping.transform(shape_grads2, shape_grads1,
-                           mapping_data, mapping_covariant);
-                                           // transpose back
-          for (unsigned int q=0; q<n_q_points; ++q)
-            shape_grads2[q] = transpose(shape_grads1[q]);
+          switch (subface)
+            {
+              case 0:
+                {
+                  const Quadrature<dim - 2>& edge_quadrature
+                    = QProjector<dim - 2>::project_to_child
+                      (reference_edge_quadrature, 0);
+                  const unsigned int n_edge_points = edge_quadrature.size ();
+                  const std::vector<Point<dim - 2> >&
+                    edge_quadrature_points = edge_quadrature.get_points ();
+
+                                  // Let us begin with the
+                                  // interpolation part.
+                  for (unsigned int q_point = 0; q_point < n_edge_points;
+                       ++q_point)
+                    {
+                      const double
+                        weight = 2.0 * edge_quadrature.weight (q_point);
+
+                      for (unsigned int i = 0; i < 2; ++i)
+                        for (unsigned int dof = 0; dof < this->dofs_per_face;
+                             ++dof)
+                          {
+                            interpolation_matrix (i * source_fe.degree, dof)
+                              += weight
+                                 * this->shape_value_component
+                                   (this->face_to_cell_index (dof, 4),
+                                    Point<dim>
+                                    (0.5 * i,
+                                     edge_quadrature_points[q_point] (0), 0.0),
+                                     1);
+                            interpolation_matrix ((i + 2) * source_fe.degree,
+                                                  dof)
+                              += weight
+                                 * this->shape_value_component
+                                   (this->face_to_cell_index (dof, 4),
+                                    Point<dim>
+                                    (edge_quadrature_points[q_point] (0),
+                                     0.5 * i, 0.0), 0);
+                          }
+                    }
+                  
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                  for (unsigned int i = 0; i < 2; ++i)
+                    for (unsigned int dof = 0; dof < this->dofs_per_face;
+                         ++dof)
+                      {
+                        if (std::abs (interpolation_matrix
+                                      (i * source_fe.degree, dof)) < 1e-14)
+                          interpolation_matrix (i * source_fe.degree, dof)
+                            = 0.0;
+                  
+                        if (std::abs (interpolation_matrix
+                                      ((i + 2) * source_fe.degree, dof))
+                              < 1e-14)
+                          interpolation_matrix ((i + 2) * source_fe.degree,
+                                                dof) = 0.0;
+                      }
+
+                                  // If the degree is greater
+                                  // than 0, then we have still
+                                  // some higher order edge
+                                  // shape functions to
+                                  // consider.
+                                  // Here the projection part
+                                  // starts. The dof values
+                                  // are obtained by solving
+                                  // a linear system of
+                                  // equations.
+                  if (deg > 0)
+                    {
+                                         // We start with projection
+                                         // on the higher order edge
+                                         // shape function.
+                      const QGauss<dim - 1> reference_face_quadrature
+                        (this->degree);
+                      const Quadrature<dim - 1>& face_quadrature
+                        = QProjector<dim - 1>::project_to_child
+                          (reference_face_quadrature, 0);
+                      const std::vector<Polynomials::Polynomial<double> >&
+                        legendre_polynomials
+                          = Polynomials::Legendre::generate_complete_basis
+                            (deg);
+                      const std::vector<Polynomials::Polynomial<double> >&
+                        lobatto_polynomials
+                          = Polynomials::Lobatto::generate_complete_basis
+                            (this->degree);
+                      const std::vector<Point<dim - 1> >&
+                        face_quadrature_points = face_quadrature.get_points ();
+                      const unsigned int& n_face_points
+                        = face_quadrature.size ();
+                      FullMatrix<double> assembling_matrix
+                        (deg, n_edge_points);
+                      FullMatrix<double> system_matrix (deg, deg);
+                      FullMatrix<double> system_matrix_inv (deg, deg);
+                      std::vector<Polynomials::Polynomial<double> >
+                        lobatto_polynomials_grad (this->degree);
+                      
+                      for (unsigned int i = 0; i <= deg; ++i)
+                        lobatto_polynomials_grad[i]
+                          = lobatto_polynomials[i + 1].derivative ();
+
+                                  // Shifted and scaled
+                                  // quadrature points on
+                                  // the four edges of a
+                                  // face.
+                      std::vector<std::vector<Point<dim> > >
+                        edge_quadrature_points_full_dim
+                        (GeometryInfo<dim>::lines_per_face);
+                  
+                      for (unsigned int line = 0;
+                           line < GeometryInfo<dim>::lines_per_face; ++line)
+                        edge_quadrature_points_full_dim.resize (n_edge_points);
+                                  
+                      for (unsigned int q_point = 0; q_point < n_edge_points;
+                           ++q_point)
+                        {
+                          edge_quadrature_points_full_dim[0][q_point]
+                            = Point<dim> (0.0,
+                                          edge_quadrature_points[q_point] (0),
+                                          0.0);
+                          edge_quadrature_points_full_dim[1][q_point]
+                            = Point<dim> (0.5,
+                                          edge_quadrature_points[q_point] (0),
+                                          0.0);
+                          edge_quadrature_points_full_dim[2][q_point]
+                            = Point<dim> (edge_quadrature_points[q_point] (0),
+                                          0.0, 0.0);
+                          edge_quadrature_points_full_dim[3][q_point]
+                            = Point<dim> (edge_quadrature_points[q_point] (0),
+                                          0.5, 0.0);
+                        }
+                  
+                      Vector<double> solution (deg);
+                      Vector<double> system_rhs (deg);
+
+                      for (unsigned int dof = 0; dof < this->dofs_per_face;
+                           ++dof)
+                        {
+                                  // Set up the system matrix.
+                                  // This can be used for all
+                                  // edges.
+                             for (unsigned int q_point = 0;
+                                  q_point < n_edge_points; ++q_point)
+                               {
+                                     const double tmp
+                                       = 2.0 * edge_quadrature_points[q_point] (0);
+                                     const double weight
+                                       = std::sqrt (2.0 * edge_quadrature.weight
+                                                          (q_point));
+
+                              for (unsigned int i = 0; i < deg; ++i)
+                                assembling_matrix (i, q_point)
+                                  = weight
+                                    * lobatto_polynomials_grad[i + 1].value
+                                      (tmp);
+                               }
+                     
+                          assembling_matrix.mTmult (system_matrix,
+                                                    assembling_matrix);
+                          system_matrix_inv.invert (system_matrix);
+                     
+                          for (unsigned int line = 0;
+                               line < GeometryInfo<dim>::lines_per_face;
+                               ++line)
+                            {
+                                  // Set up the right hand side.
+                             system_rhs = 0;
+                       
+                              for (unsigned int q_point = 0;
+                                   q_point < n_edge_points; ++q_point)
+                                {
+                                  const double right_hand_side_value
+                                    = std::sqrt (2.0 * edge_quadrature.weight
+                                                       (q_point))
+                                      * (this->shape_value_component
+                                         (this->face_to_cell_index (dof, 4),
+                                          edge_quadrature_points_full_dim[line][q_point],
+                                          1)
+                                         - interpolation_matrix
+                                           (line * source_fe.degree, dof));
+                                  const double tmp
+                                    = 2.0 * edge_quadrature_points[q_point] (0);
+                                 
+                                  for (unsigned int i = 0; i < deg; ++i)
+                                    system_rhs (i)
+                                      += right_hand_side_value
+                                         * lobatto_polynomials_grad[i + 1].value
+                                           (tmp);
+                                }
+
+                              system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                              for (unsigned int i = 0; i < deg; ++i)
+                                if (std::abs (solution (i)) > 1e-14)
+                                  interpolation_matrix
+                                    (line * source_fe.degree + i + 1, dof)
+                                    = solution (i);
+                            }
+
+                          assembling_matrix.reinit (deg * this->degree,
+                                                    n_face_points);
+                          system_rhs.reinit (assembling_matrix.m ());
+                          system_rhs = 0;
+
+                                  // Now we project the remaining
+                                  // part on the face shape
+                                  // functions. First on the
+                                  // horizontal ones, then on
+                                  // the vertical ones. 
+                          for (unsigned int q_point = 0;
+                               q_point < n_face_points; ++q_point)
+                            {
+                              const Point<dim> quadrature_point
+                                (2.0 * face_quadrature_points[q_point] (0),
+                                 2.0 * face_quadrature_points[q_point] (1),
+                                 0.0);
+                              double right_hand_side_value
+                                = this->shape_value_component
+                                  (this->face_to_cell_index (dof, 4),
+                                   Point<dim>
+                                   (face_quadrature_points[q_point] (0),
+                                    face_quadrature_points[q_point] (1), 0.0),
+                                   1);
+
+                              for (unsigned int i = 0; i < 2; ++i)
+                                for (unsigned int j = 0; j < source_fe.degree;
+                                     ++j)
+                                  right_hand_side_value
+                                    -= interpolation_matrix
+                                       (i * source_fe.degree + j, dof)
+                                       * source_fe.shape_value_component
+                                         (i * source_fe.degree + j,
+                                          quadrature_point, 1);
+                        
+                              right_hand_side_value
+                                *= 4.0 * face_quadrature.weight (q_point);
+                              
+                              const double weight
+                                = std::sqrt (4.0 * face_quadrature.weight
+                                                   (q_point));
+                        
+                              for (unsigned int i = 0; i <= deg; ++i)
+                                {
+                                  const double L_i
+                                    = legendre_polynomials[i].value
+                                      (quadrature_point (0));
+                                  const double tmp1 = weight * L_i;
+                                  const double tmp2
+                                    = right_hand_side_value * L_i;
+                           
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    {
+                                         const double l_j
+                                           = lobatto_polynomials[j + 2].value
+                                             (quadrature_point (1));
+                                         
+                                         assembling_matrix (i * deg + j, q_point)
+                                           = tmp1 * l_j;
+                                      system_rhs (i * deg + j) +=  tmp2 * l_j;
+                                    }
+                                }
+                            }
+
+                          system_matrix.reinit (assembling_matrix.m (),
+                                                assembling_matrix.m ());
+                          assembling_matrix.mTmult (system_matrix,
+                                                    assembling_matrix);
+                          system_matrix_inv.reinit (system_matrix.m (),
+                                                    system_matrix.m ());
+                          system_matrix_inv.invert (system_matrix);
+                          solution.reinit (system_matrix_inv.m ());
+                          system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                          for (unsigned int i = 0; i <= deg; ++i)
+                            for (unsigned int j = 0; j < deg; ++j)
+                              if (std::abs (solution (i * deg + j)) > 1e-14)
+                                interpolation_matrix
+                                  ((i + 4) * source_fe.degree + j - i, dof)
+                                  = solution (i * deg + j);
+                          
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                          system_rhs = 0;
+
+                          for (unsigned int q_point = 0;
+                               q_point < n_face_points; ++q_point)
+                            {
+                              const Point<dim> quadrature_point
+                                (2.0 * face_quadrature_points[q_point] (0),
+                                 2.0 * face_quadrature_points[q_point] (1),
+                                 0.0);
+                              double right_hand_side_value
+                                = this->shape_value_component
+                                  (this->face_to_cell_index (dof, 4),
+                                   Point<dim>
+                                   (face_quadrature_points[q_point] (0),
+                                    face_quadrature_points[q_point] (1), 0.0),
+                                   0);
+
+                              for (unsigned int i = 0; i < 2; ++i)
+                                for (unsigned int j = 0; j < source_fe.degree;
+                                     ++j)
+                                  right_hand_side_value
+                                    -= interpolation_matrix
+                                       ((i + 2) * source_fe.degree + j, dof)
+                                       * source_fe.shape_value_component
+                                         (i * source_fe.degree + j,
+                                          quadrature_point, 0);
+
+                              right_hand_side_value
+                                *= 4.0 * face_quadrature.weight (q_point);
+                        
+                              for (unsigned int i = 0; i <= deg; ++i)
+                                {
+                                  const double L_i
+                                    = legendre_polynomials[i].value
+                                      (quadrature_point (0));
+                                  const double tmp = right_hand_side_value
+                                                     * L_i;
+                           
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    system_rhs (i * deg + j)
+                                      += tmp
+                                         * lobatto_polynomials[j + 2].value
+                                           (quadrature_point (1));
+                                }
+                            }
+
+                          system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                          for (unsigned int i = 0; i <= deg; ++i)
+                            for (unsigned int j = 0; j < deg; ++j)
+                              if (std::abs (solution (i * deg + j)) > 1e-14)
+                                interpolation_matrix
+                                (i + (j + source_fe.degree + 3)
+                                 * source_fe.degree, dof) = solution (i * deg
+                                                                      + j);
+                        }
+                    }
+
+                  break;
+                }
+
+              case 1:
+                {
+                  const Quadrature<dim - 2>& edge_quadrature_x
+                    = QProjector<dim - 2>::project_to_child
+                      (reference_edge_quadrature, 1);
+                  const Quadrature<dim - 2>& edge_quadrature_y
+                    = QProjector<dim - 2>::project_to_child
+                      (reference_edge_quadrature, 0);
+                  const std::vector<Point<dim - 2> >&
+                    edge_quadrature_x_points = edge_quadrature_x.get_points ();
+                  const std::vector<Point<dim - 2> >&
+                    edge_quadrature_y_points = edge_quadrature_y.get_points ();
+                  const unsigned int& n_edge_points
+                    = edge_quadrature_x.size ();
+
+                                  // Let us begin with the
+                                  // interpolation part.
+                  for (unsigned int q_point = 0; q_point < n_edge_points;
+                       ++q_point)
+                    {
+                      const double weight
+                        = 2.0 * edge_quadrature_x.weight (q_point);
+
+                      for (unsigned int i = 0; i < 2; ++i)
+                        for (unsigned int dof = 0; dof < this->dofs_per_face;
+                             ++dof)
+                          {
+                            interpolation_matrix (i * source_fe.degree, dof)
+                              += this->shape_value_component
+                                 (this->face_to_cell_index (dof, 4),
+                                  Point<dim>
+                                  (0.5 * (i + 1),
+                                   edge_quadrature_y_points[q_point] (0), 0.0),
+                                  1);
+                            interpolation_matrix
+                            ((i + 2) * source_fe.degree, dof)
+                              += this->shape_value_component
+                                 (this->face_to_cell_index (dof, 4),
+                                  Point<dim>
+                                  (edge_quadrature_x_points[q_point] (0),
+                                   0.5 * i, 0.0), 0);
+                          }
+                    }
+               
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                  for (unsigned int i = 0; i < 2; ++i)
+                    for (unsigned int dof = 0; dof < this->dofs_per_face;
+                         ++dof)
+                      {
+                        if (std::abs (interpolation_matrix
+                                      (i * source_fe.degree, dof)) < 1e-14)
+                          interpolation_matrix (i * source_fe.degree, dof)
+                            = 0.0;
+                     
+                        if (std::abs (interpolation_matrix
+                                      ((i + 2) * source_fe.degree, dof))
+                              < 1e-14)
+                          interpolation_matrix ((i + 2) * source_fe.degree,
+                                                dof) = 0.0;
+                      }
+
+                                  // If the degree is greater
+                                  // than 0, then we have still
+                                  // some higher order edge
+                                  // shape functions to
+                                  // consider.
+                                  // Here the projection part
+                                  // starts. The dof values
+                                  // are obtained by solving
+                                  // a linear system of
+                                  // equations.
+                  if (deg > 0)
+                    {
+                                         // We start with projection
+                                         // on the higher order edge
+                                         // shape function.
+                      const QGauss<dim - 1> reference_face_quadrature
+                        (this->degree);
+                      const Quadrature<dim - 1>& face_quadrature
+                        = QProjector<dim - 1>::project_to_child
+                          (reference_face_quadrature, 1);
+                      const std::vector<Point<dim - 1> >&
+                        face_quadrature_points = face_quadrature.get_points ();
+                      const std::vector<Polynomials::Polynomial<double> >&
+                        legendre_polynomials
+                          = Polynomials::Legendre::generate_complete_basis
+                            (deg);
+                      const std::vector<Polynomials::Polynomial<double> >&
+                        lobatto_polynomials
+                          = Polynomials::Lobatto::generate_complete_basis
+                            (this->degree);
+                      const unsigned int&
+                        n_face_points = face_quadrature.size ();
+                      FullMatrix<double> assembling_matrix (deg,
+                                                            n_edge_points);
+                      FullMatrix<double> system_matrix (deg, deg);
+                      FullMatrix<double> system_matrix_inv (deg, deg);
+                      std::vector<Polynomials::Polynomial<double> >
+                        lobatto_polynomials_grad (this->degree);
+
+                      for (unsigned int i = 0;
+                           i < lobatto_polynomials_grad.size (); ++i)
+                        lobatto_polynomials_grad[i]
+                          = lobatto_polynomials[i + 1].derivative ();
+                     
+                                  // Shifted and scaled
+                                  // quadrature points and
+                                  // weights on the four
+                                  // edges of a face.
+                      std::vector<std::vector<double> > edge_quadrature_points
+                        (GeometryInfo<dim>::lines_per_face);
+                      std::vector<std::vector<double> >
+                        edge_quadrature_weights
+                          (GeometryInfo<dim>::lines_per_face);
+                      std::vector<std::vector<Point<dim> > >
+                        edge_quadrature_points_full_dim
+                          (GeometryInfo<dim>::lines_per_face);
+                  
+                      for (unsigned int line = 0;
+                           line < GeometryInfo<dim>::lines_per_face; ++line)
+                        {
+                             edge_quadrature_points.resize (n_edge_points);
+                          edge_quadrature_points_full_dim.resize
+                            (n_edge_points);
+                          edge_quadrature_weights.resize (n_edge_points);
+                        }
+                  
+                      for (unsigned int q_point = 0; q_point < n_edge_points;
+                           ++q_point)
+                        {
+                             edge_quadrature_points[0][q_point]
+                               = 2.0 * edge_quadrature_y_points[q_point] (0);
+                             edge_quadrature_points[1][q_point]
+                               = edge_quadrature_points[0][q_point];
+                             edge_quadrature_points[2][q_point]
+                               = 2.0 * edge_quadrature_x_points[q_point] (0)
+                                 - 1.0;
+                             edge_quadrature_points[3][q_point]
+                               = edge_quadrature_points[2][q_point];
+                          edge_quadrature_points_full_dim[0][q_point]
+                            = Point<dim>
+                              (0.5, edge_quadrature_y_points[q_point] (0),
+                               0.0);
+                          edge_quadrature_points_full_dim[1][q_point]
+                            = Point<dim>
+                              (1.0, edge_quadrature_y_points[q_point] (0),
+                               0.0);
+                          edge_quadrature_points_full_dim[2][q_point]
+                            = Point<dim>
+                              (edge_quadrature_x_points[q_point] (0), 0.0,
+                               0.0);
+                          edge_quadrature_points_full_dim[3][q_point]
+                            = Point<dim>
+                              (edge_quadrature_x_points[q_point] (0), 0.5,
+                               0.0);
+                          edge_quadrature_weights[0][q_point]
+                            = std::sqrt (2.0 * edge_quadrature_y.weight
+                                               (q_point));
+                          edge_quadrature_weights[1][q_point]
+                            = edge_quadrature_weights[0][q_point];
+                          edge_quadrature_weights[2][q_point]
+                            = std::sqrt (2.0 * edge_quadrature_x.weight
+                                               (q_point));
+                          edge_quadrature_weights[3][q_point]
+                            = edge_quadrature_weights[2][q_point];
+                        }
+                  
+                      Vector<double> system_rhs (system_matrix.m ());
+                      Vector<double> solution (system_rhs.size ());
+
+                      for (unsigned int dof = 0; dof < this->dofs_per_face;
+                          ++dof)
+                        {
+                                  // Set up the system matrix.
+                                  // This can be used for all
+                                  // edges.
+                             for (unsigned int q_point = 0;
+                                  q_point < n_edge_points; ++q_point)
+                               {
+                                      const double tmp
+                                        = 2.0 * edge_quadrature_y_points[q_point] (0);
+                                      const double weight
+                                        = std::sqrt (2.0 * edge_quadrature_y.weight
+                                                           (q_point));
+
+                               for (unsigned int i = 0; i < deg; ++i)
+                                 assembling_matrix (i, q_point)
+                                   = weight
+                                     * lobatto_polynomials_grad[i + 1].value
+                                       (tmp);
+                               }
+                     
+                          assembling_matrix.mTmult (system_matrix,
+                                                    assembling_matrix);
+                          system_matrix_inv.invert (system_matrix);
+                     
+                          for (unsigned int line = 0;
+                               line < GeometryInfo<dim - 1>::lines_per_cell;
+                               ++line)
+                            {
+                                  // Set up the right hand side.
+                              system_rhs = 0;
+                           
+                              for (unsigned int q_point = 0;
+                                   q_point < n_edge_points; ++q_point)
+                                {
+                                   const double right_hand_side_value
+                                     = edge_quadrature_weights[line][q_point]
+                                       * (this->shape_value_component
+                                          (this->face_to_cell_index (dof, 4),
+                                           edge_quadrature_points_full_dim[line][q_point],
+                                           1) - interpolation_matrix
+                                                (line * source_fe.degree,
+                                                 dof));
+                                 
+                                   for (unsigned int i = 0; i < deg; ++i)
+                                     system_rhs (i)
+                                       += right_hand_side_value
+                                          * lobatto_polynomials_grad[i + 1].value
+                                            (edge_quadrature_points[line][q_point]);
+                                }
+
+                              system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                              for (unsigned int i = 0; i < solution.size ();
+                                   ++i)
+                                if (std::abs (solution (i)) > 1e-14)
+                                  interpolation_matrix
+                                  (line * source_fe.degree + i + 1, dof)
+                                    = solution (i);
+                            }
+
+                                  // Now we project the remaining
+                                  // part on the face shape
+                                  // functions. First on the
+                                  // horizontal ones, then on
+                                  // the vertical ones. 
+                          assembling_matrix.reinit (deg * this->degree,
+                                                    n_face_points);
+                          system_rhs.reinit (assembling_matrix.m ());
+                          system_rhs = 0;
+
+                          for (unsigned int q_point = 0;
+                               q_point < n_face_points; ++q_point)
+                            {
+                              const Point<dim> quadrature_point
+                                (2.0 * face_quadrature_points[q_point] (0)
+                                 - 1.0,
+                                 2.0 * face_quadrature_points[q_point] (1),
+                                 0.0);
+                              double right_hand_side_value
+                                = this->shape_value_component
+                                  (this->face_to_cell_index (dof, 4),
+                                   Point<dim>
+                                   (face_quadrature_points[q_point] (0),
+                                    face_quadrature_points[q_point] (1), 0),
+                                   1);
+
+                              for (unsigned int i = 0; i < 2; ++i)
+                                for (unsigned int j = 0; j < source_fe.degree;
+                                     ++j)
+                                  right_hand_side_value
+                                    -= interpolation_matrix
+                                       (i * source_fe.degree + j, dof)
+                                       * source_fe.shape_value_component
+                                         (i * source_fe.degree + j,
+                                          quadrature_point, 1);
+                        
+                              right_hand_side_value
+                                *= 4.0 * face_quadrature.weight (q_point);
+                                
+                              const double weight
+                                = std::sqrt (4.0 * face_quadrature.weight
+                                                   (q_point));
+                        
+                              for (unsigned int i = 0; i <= deg; ++i)
+                                {
+                                  const double L_i
+                                    = legendre_polynomials[i].value
+                                      (quadrature_point (0));
+                                  const double tmp1 = weight * L_i;
+                                  const double tmp2 = right_hand_side_value
+                                                      * L_i;
+                           
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    {
+                                         const double l_j
+                                           = lobatto_polynomials[j + 2].value
+                                             (quadrature_point (1));
+                                         
+                                         assembling_matrix (i * deg + j, q_point)
+                                           = tmp1 * l_j;
+                                      system_rhs (i * deg + j) +=  tmp2 * l_j;
+                                    }
+                                }
+                            }
+
+                          system_matrix.reinit (assembling_matrix.m (),
+                                                assembling_matrix.m ());
+                          assembling_matrix.mTmult (system_matrix,
+                                                    assembling_matrix);
+                          system_matrix_inv.reinit (system_matrix.m (),
+                                                    system_matrix.m ());
+                          system_matrix_inv.invert (system_matrix);
+                          solution.reinit (system_matrix_inv.m ());
+                          system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                          for (unsigned int i = 0; i <= deg; ++i)
+                            for (unsigned int j = 0; j < deg; ++j)
+                              if (std::abs (solution (i * deg + j)) > 1e-14)
+                                interpolation_matrix
+                                ((i + 4) * source_fe.degree + j - i, dof)
+                                  = solution (i * deg + j);
+                          
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                          system_rhs = 0;
+
+                          for (unsigned int q_point = 0;
+                               q_point < n_face_points; ++q_point)
+                            {
+                              const Point<dim> quadrature_point
+                                (2.0 * face_quadrature_points[q_point] (0)
+                                 - 1.0,
+                                 2.0 * face_quadrature_points[q_point] (1),
+                                 0.0);
+                              double right_hand_side_value
+                                = this->shape_value_component
+                                  (this->face_to_cell_index (dof, 4),
+                                   Point<dim>
+                                   (face_quadrature_points[q_point] (0),
+                                    face_quadrature_points[q_point] (1), 0),
+                                   0);
+
+                              for (unsigned int i = 0; i < 2; ++i)
+                                for (unsigned int j = 0; j < source_fe.degree;
+                                     ++j)
+                                  right_hand_side_value
+                                    -= interpolation_matrix
+                                       ((i + 2) * source_fe.degree + j, dof)
+                                       * source_fe.shape_value_component
+                                         (i * source_fe.degree + j,
+                                          quadrature_point, 0);
+
+                              right_hand_side_value
+                                *= 4.0 * face_quadrature.weight (q_point);
+                        
+                              for (unsigned int i = 0; i <= deg; ++i)
+                                {
+                                  const double L_i
+                                    = legendre_polynomials[i].value
+                                      (quadrature_point (0));
+                                  const double tmp
+                                    = right_hand_side_value * L_i;
+                           
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    system_rhs (i * deg + j)
+                                      += tmp
+                                         * lobatto_polynomials[j + 2].value
+                                           (quadrature_point (1));
+                                }
+                            }
+
+                          system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                          for (unsigned int i = 0; i <= deg; ++i)
+                            for (unsigned int j = 0; j < deg; ++j)
+                              if (std::abs (solution (i * deg + j)) > 1e-14)
+                                interpolation_matrix
+                                (i + (j + source_fe.degree + 3)
+                                     * source_fe.degree, dof)
+                                  = solution (i * deg + j);
+                        }
+                    }
+
+                  break;
+                }
+
+              case 2:
+                {
+                  const Quadrature<dim - 2>& edge_quadrature_x
+                    = QProjector<dim - 2>::project_to_child
+                      (reference_edge_quadrature, 0);
+                  const Quadrature<dim - 2>& edge_quadrature_y
+                    = QProjector<dim - 2>::project_to_child
+                      (reference_edge_quadrature, 1);
+                  const unsigned int& n_edge_points
+                    = edge_quadrature_x.size ();
+                  const std::vector<Point<dim - 2> >&
+                    edge_quadrature_x_points = edge_quadrature_x.get_points ();
+                  const std::vector<Point<dim - 2> >&
+                    edge_quadrature_y_points = edge_quadrature_y.get_points ();
+
+                                  // Let us begin with the
+                                  // interpolation part.
+                  for (unsigned int q_point = 0; q_point < n_edge_points;
+                       ++q_point)
+                    {
+                      const double weight
+                        = 2.0 * edge_quadrature_x.weight (q_point);
+
+                      for (unsigned int i = 0; i < 2; ++i)
+                        for (unsigned int dof = 0; dof < this->dofs_per_face;
+                             ++dof)
+                          {
+                            interpolation_matrix (i * source_fe.degree, dof)
+                              += this->shape_value_component
+                                 (this->face_to_cell_index (dof, 4),
+                                  Point<dim>
+                                  (0.5 * i,
+                                   edge_quadrature_y_points[q_point] (0), 0.0),
+                                  1);
+                            interpolation_matrix ((i + 2) * source_fe.degree,
+                                                  dof)
+                              += this->shape_value_component
+                                 (this->face_to_cell_index (dof, 4),
+                                  Point<dim>
+                                  (edge_quadrature_x_points[q_point] (0),
+                                   0.5 * (i + 1), 0.0), 0);
+                          }
+                    }
+               
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                  for (unsigned int i = 0; i < 2; ++i)
+                    for (unsigned int dof = 0; dof < this->dofs_per_face;
+                         ++dof)
+                      {
+                        if (std::abs (interpolation_matrix
+                                      (i * source_fe.degree, dof)) < 1e-14)
+                          interpolation_matrix (i * source_fe.degree, dof)
+                            = 0.0;
+                        
+                        if (std::abs (interpolation_matrix
+                                      ((i + 2) * source_fe.degree, dof))
+                              < 1e-14)
+                          interpolation_matrix ((i + 2) * source_fe.degree,
+                                                dof) = 0.0;
+                      }
+
+                                  // If the degree is greater
+                                  // than 0, then we have still
+                                  // some higher order edge
+                                  // shape functions to
+                                  // consider.
+                                  // Here the projection part
+                                  // starts. The dof values
+                                  // are obtained by solving
+                                  // a linear system of
+                                  // equations.
+                  if (deg > 0)
+                    {
+                                         // We start with projection
+                                         // on the higher order edge
+                                         // shape function.
+                      const QGauss<dim - 1> reference_face_quadrature (this->degree);
+                      const Quadrature<dim - 1>& face_quadrature
+                        = QProjector<dim - 1>::project_to_child
+                          (reference_face_quadrature, 2);
+                      const std::vector<Point<dim - 1> >&
+                        face_quadrature_points = face_quadrature.get_points ();
+                      const std::vector<Polynomials::Polynomial<double> >& legendre_polynomials
+                        = Polynomials::Legendre::generate_complete_basis (deg);
+                      const std::vector<Polynomials::Polynomial<double> >& lobatto_polynomials
+                        = Polynomials::Lobatto::generate_complete_basis (this->degree);
+                      const unsigned int& n_face_points
+                        = face_quadrature.size ();
+                      FullMatrix<double> assembling_matrix (deg,
+                                                            n_edge_points);
+                      FullMatrix<double> system_matrix (deg, deg);
+                      FullMatrix<double> system_matrix_inv (deg, deg);
+                      std::vector<Polynomials::Polynomial<double> >
+                        lobatto_polynomials_grad (this->degree);
+
+                      for (unsigned int i = 0;
+                           i < lobatto_polynomials_grad.size (); ++i)
+                        lobatto_polynomials_grad[i]
+                          = lobatto_polynomials[i + 1].derivative ();
+                      
+                                  // Shifted and scaled
+                                  // quadrature points and
+                                  // weights on the four
+                                  // edges of a face.
+                      std::vector<std::vector<double> >
+                        edge_quadrature_points
+                        (GeometryInfo<dim>::lines_per_face);
+                      std::vector<std::vector<double> >
+                        edge_quadrature_weights
+                        (GeometryInfo<dim>::lines_per_face);
+                      std::vector<std::vector<Point<dim> > >
+                        edge_quadrature_points_full_dim
+                        (GeometryInfo<dim>::lines_per_face);
+                  
+                      for (unsigned int line = 0;
+                           line < GeometryInfo<dim>::lines_per_face; ++line)
+                        {
+                             edge_quadrature_points.resize (n_edge_points);
+                          edge_quadrature_points_full_dim.resize
+                            (n_edge_points);
+                          edge_quadrature_weights.resize (n_edge_points);
+                        }
+                  
+                      for (unsigned int q_point = 0; q_point < n_edge_points;
+                           ++q_point)
+                        {
+                             edge_quadrature_points[0][q_point]
+                               = 2.0 * edge_quadrature_y_points[q_point] (0)
+                                 - 1.0;
+                             edge_quadrature_points[1][q_point]
+                               = edge_quadrature_points[0][q_point];
+                             edge_quadrature_points[2][q_point]
+                               = 2.0 * edge_quadrature_x_points[q_point] (0);
+                             edge_quadrature_points[3][q_point]
+                               = edge_quadrature_points[2][q_point];
+                          edge_quadrature_points_full_dim[0][q_point]
+                            = Point<dim>
+                              (0.0, edge_quadrature_y_points[q_point] (0),
+                               0.0);
+                          edge_quadrature_points_full_dim[1][q_point]
+                            = Point<dim>
+                              (0.5, edge_quadrature_y_points[q_point] (0),
+                               0.0);
+                          edge_quadrature_points_full_dim[2][q_point]
+                            = Point<dim>
+                              (edge_quadrature_x_points[q_point] (0), 0.5,
+                               0.0);
+                          edge_quadrature_points_full_dim[3][q_point]
+                            = Point<dim>
+                              (edge_quadrature_x_points[q_point] (0), 1.0,
+                               0.0);
+                          edge_quadrature_weights[0][q_point]
+                            = std::sqrt (2.0 * edge_quadrature_y.weight
+                                               (q_point));
+                          edge_quadrature_weights[1][q_point]
+                            = edge_quadrature_weights[0][q_point];
+                          edge_quadrature_weights[2][q_point]
+                            = std::sqrt (2.0 * edge_quadrature_x.weight
+                                               (q_point));
+                          edge_quadrature_weights[3][q_point]
+                            = edge_quadrature_weights[2][q_point];
+                        }
+                      
+                      Vector<double> system_rhs (system_matrix.m ());
+                      Vector<double> solution (system_rhs.size ());
+
+                      for (unsigned int dof = 0; dof < this->dofs_per_face;
+                           ++dof)
+                        {
+                                  // Set up the system matrix.
+                                  // This can be used for all
+                                  // edges.
+                             for (unsigned int q_point = 0;
+                                  q_point < n_edge_points; ++q_point)
+                               {
+                                     const double weight
+                                       = std::sqrt (2.0 * edge_quadrature_y.weight
+                                                          (q_point));
+                                     const double tmp
+                                       = 2.0 * edge_quadrature_y_points[q_point] (0)
+                                         - 1.0;
+
+                              for (unsigned int i = 0; i < deg; ++i)
+                                assembling_matrix (i, q_point)
+                                  = weight
+                                    * lobatto_polynomials_grad[i + 1].value
+                                      (tmp);
+                               }
+                     
+                          assembling_matrix.mTmult (system_matrix,
+                                                    assembling_matrix);
+                          system_matrix_inv.invert (system_matrix);
+                     
+                          for (unsigned int line = 0;
+                               line < GeometryInfo<dim - 1>::lines_per_cell;
+                               ++line)
+                            {
+                                  // Set up the right hand side.
+                              system_rhs = 0;
+                           
+                              for (unsigned int q_point = 0;
+                                   q_point < n_edge_points; ++q_point)
+                                {
+                                  const double right_hand_side_value
+                                    = edge_quadrature_weights[line][q_point]
+                                      * (this->shape_value_component
+                                         (this->face_to_cell_index (dof, 4),
+                                          edge_quadrature_points_full_dim[line][q_point],
+                                          1) - interpolation_matrix
+                                               (line * source_fe.degree, dof));
+                                 
+                                  for (unsigned int i = 0; i < deg; ++i)
+                                    system_rhs (i)
+                                      += right_hand_side_value
+                                         * lobatto_polynomials_grad[i + 1].value
+                                           (edge_quadrature_points[line][q_point]);
+                                }
+
+                              system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                              for (unsigned int i = 0; i < solution.size ();
+                                   ++i)
+                                if (std::abs (solution (i)) > 1e-14)
+                                  interpolation_matrix
+                                  (line * source_fe.degree + i + 1, dof)
+                                    = solution (i);
+                            }
+
+                          assembling_matrix.reinit (deg * this->degree,
+                                                    n_face_points);
+                          system_rhs.reinit (assembling_matrix.m ());
+                          system_rhs = 0;
+
+                                  // Now we project the remaining
+                                  // part on the face shape
+                                  // functions. First on the
+                                  // horizontal ones, then on
+                                  // the vertical ones. 
+                          for (unsigned int q_point = 0;
+                               q_point < n_face_points; ++q_point)
+                            {
+                              const Point<dim> quadrature_point
+                                (2.0 * face_quadrature_points[q_point] (0),
+                                 2.0 * face_quadrature_points[q_point] (1)
+                                 - 1.0, 0.0);
+                              double right_hand_side_value
+                                = this->shape_value_component
+                                  (this->face_to_cell_index (dof, 4),
+                                   Point<dim>
+                                   (face_quadrature_points[q_point] (0),
+                                    face_quadrature_points[q_point] (1), 0.0),
+                                   1);
+
+                              for (unsigned int i = 0; i < 2; ++i)
+                                for (unsigned int j = 0; j < source_fe.degree;
+                                     ++j)
+                                  right_hand_side_value
+                                    -= interpolation_matrix
+                                       (i * source_fe.degree + j, dof)
+                                       * source_fe.shape_value_component
+                                         (i * source_fe.degree + j,
+                                          quadrature_point, 1);
+                        
+                              right_hand_side_value
+                                *= 4.0 * face_quadrature.weight (q_point);
+                              
+                              const double weight
+                                = std::sqrt (4.0 * reference_face_quadrature.weight
+                                                   (q_point));
+                        
+                              for (unsigned int i = 0; i <= deg; ++i)
+                                {
+                                  const double L_i
+                                    = legendre_polynomials[i].value
+                                      (quadrature_point (0));
+                                  const double tmp1 = weight * L_i;
+                                  const double tmp2
+                                    = right_hand_side_value * L_i;
+                           
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    {
+                                         const double l_j
+                                           = lobatto_polynomials[j + 2].value
+                                             (quadrature_point (1));
+                                         
+                                         assembling_matrix (i * deg + j, q_point)
+                                           = tmp1 * l_j;
+                                      system_rhs (i * deg + j) +=  tmp2 * l_j;
+                                    }
+                                }
+                            }
+
+                          system_matrix.reinit (assembling_matrix.m (),
+                                                assembling_matrix.m ());
+                          assembling_matrix.mTmult (system_matrix,
+                                                    assembling_matrix);
+                          system_matrix_inv.reinit (system_matrix.m (),
+                                                    system_matrix.m ());
+                          system_matrix_inv.invert (system_matrix);
+                          solution.reinit (system_matrix_inv.m ());
+                          system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                          for (unsigned int i = 0; i <= deg; ++i)
+                            for (unsigned int j = 0; j < deg; ++j)
+                              if (std::abs (solution (i * deg + j)) > 1e-14)
+                                interpolation_matrix
+                                ((i + 4) * source_fe.degree + j - i, dof)
+                                  = solution (i * deg + j);
+                          
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                          system_rhs = 0;
+
+                          for (unsigned int q_point = 0;
+                               q_point < n_face_points; ++q_point)
+                            {
+                              const Point<dim> quadrature_point
+                                (2.0 * face_quadrature_points[q_point] (0),
+                                 2.0 * face_quadrature_points[q_point] (1)
+                                 - 1.0, 0.0);
+                              double right_hand_side_value
+                                = this->shape_value_component
+                                  (this->face_to_cell_index (dof, 4),
+                                   Point<dim>
+                                   (face_quadrature_points[q_point] (0),
+                                    face_quadrature_points[q_point] (1), 0.0),
+                                   0);
+
+                              for (unsigned int i = 0; i < 2; ++i)
+                                for (unsigned int j = 0; j < source_fe.degree;
+                                     ++j)
+                                  right_hand_side_value
+                                    -= interpolation_matrix
+                                       ((i + 2) * source_fe.degree + j, dof)
+                                       * source_fe.shape_value_component
+                                         (i * source_fe.degree + j,
+                                          quadrature_point, 0);
+
+                              right_hand_side_value *= 4.0 * face_quadrature.weight (q_point);
+                       
+                              for (unsigned int i = 0; i <= deg; ++i)
+                                {
+                                  const double L_i
+                                    = legendre_polynomials[i].value
+                                      (quadrature_point (0));
+                                  const double tmp = right_hand_side_value * L_i;
+                          
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    system_rhs (i * deg + j)
+                                      += tmp
+                                         * lobatto_polynomials[j + 2].value
+                                           (quadrature_point (1));
+                                }
+                            }
+
+                          system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                          for (unsigned int i = 0; i <= deg; ++i)
+                            for (unsigned int j = 0; j < deg; ++j)
+                              if (std::abs (solution (i * deg + j)) > 1e-14)
+                                interpolation_matrix
+                                (i + (j + source_fe.degree + 3)
+                                 * source_fe.degree, dof)
+                                  = solution (i * deg + j);
+                        }
+                    }
+
+                  break;
+                }
+
+              case 3:
+                {
+                  const Quadrature<dim - 2>& edge_quadrature
+                    = QProjector<dim - 2>::project_to_child
+                      (reference_edge_quadrature, 1);
+                  const unsigned int& n_edge_points = edge_quadrature.size ();
+                  const std::vector<Point<dim - 2> >&
+                    edge_quadrature_points = edge_quadrature.get_points ();
+
+                                  // Let us begin with the
+                                  // interpolation part.
+                  for (unsigned int q_point = 0; q_point < n_edge_points;
+                       ++q_point)
+                    {
+                      const double weight
+                        = 2.0 * edge_quadrature.weight (q_point);
+
+                      for (unsigned int i = 0; i < 2; ++i)
+                        for (unsigned int dof = 0; dof < this->dofs_per_face;
+                             ++dof)
+                          {
+                            interpolation_matrix (i * source_fe.degree, dof)
+                              += this->shape_value_component
+                                 (this->face_to_cell_index (dof, 4),
+                                  Point<dim>
+                                  (0.5 * (i + 1),
+                                   edge_quadrature_points[q_point] (0), 0.0),
+                                  1);
+                            interpolation_matrix ((i + 2) * source_fe.degree,
+                                                  dof)
+                              += this->shape_value_component
+                                 (this->face_to_cell_index (dof, 4),
+                                  Point<dim>
+                                  (edge_quadrature_points[q_point] (0),
+                                   0.5 * (i + 1), 0.0), 0);
+                          }
+                    }
+               
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                  for (unsigned int i = 0; i < 2; ++i)
+                    for (unsigned int dof = 0; dof < this->dofs_per_face;
+                         ++dof)
+                      {
+                        if (std::abs (interpolation_matrix
+                                      (i * source_fe.degree, dof)) < 1e-14)
+                          interpolation_matrix (i * source_fe.degree, dof)
+                            = 0.0;
+                     
+                        if (std::abs (interpolation_matrix
+                                      ((i + 2) * source_fe.degree, dof))
+                              < 1e-14)
+                          interpolation_matrix ((i + 2) * source_fe.degree,
+                                                dof) = 0.0;
+                      }
+
+                                  // If the degree is greater
+                                  // than 0, then we have still
+                                  // some higher order edge
+                                  // shape functions to
+                                  // consider.
+                                  // Here the projection part
+                                  // starts. The dof values
+                                  // are obtained by solving
+                                  // a linear system of
+                                  // equations.
+                  if (deg > 1)
+                    {
+                                         // We start with projection
+                                         // on the higher order edge
+                                         // shape function.
+                      const QGauss<dim - 1>
+                        reference_face_quadrature (this->degree);
+                      const Quadrature<dim - 1>& face_quadrature
+                        = QProjector<dim - 1>::project_to_child
+                          (reference_face_quadrature, 3);
+                      const std::vector<Point<dim - 1> >&
+                        face_quadrature_points = face_quadrature.get_points ();
+                      const std::vector<Polynomials::Polynomial<double> >&
+                        legendre_polynomials
+                          = Polynomials::Legendre::generate_complete_basis
+                            (deg);
+                      const std::vector<Polynomials::Polynomial<double> >&
+                        lobatto_polynomials
+                          = Polynomials::Lobatto::generate_complete_basis
+                            (this->degree);
+                      const unsigned int& n_face_points
+                        = face_quadrature.size ();
+                      FullMatrix<double> assembling_matrix (deg,
+                                                            n_edge_points);
+                      FullMatrix<double> system_matrix (deg, deg);
+                      FullMatrix<double> system_matrix_inv (deg, deg);
+                      std::vector<Polynomials::Polynomial<double> >
+                        lobatto_polynomials_grad (this->degree);
+
+                      for (unsigned int i = 0;
+                           i < lobatto_polynomials_grad.size (); ++i)
+                        lobatto_polynomials_grad[i]
+                          = lobatto_polynomials[i + 1].derivative ();
+                      
+                                  // Shifted and scaled
+                                  // quadrature points on
+                                  // the four edges of a
+                                  // face.
+                      std::vector<std::vector<Point<dim> > >
+                        edge_quadrature_points_full_dim
+                        (GeometryInfo<dim>::lines_per_face);
+                  
+                      for (unsigned int line = 0;
+                           line < GeometryInfo<dim>::lines_per_face; ++line)
+                        edge_quadrature_points_full_dim.resize
+                          (n_edge_points);
+                  
+                      for (unsigned int q_point = 0; q_point < n_edge_points;
+                           ++q_point)
+                        {
+                          edge_quadrature_points_full_dim[0][q_point]
+                            = Point<dim>
+                              (0.5, edge_quadrature_points[q_point] (0), 0.0);
+                          edge_quadrature_points_full_dim[1][q_point]
+                            = Point<dim>
+                              (1.0, edge_quadrature_points[q_point] (0), 0.0);
+                          edge_quadrature_points_full_dim[2][q_point]
+                            = Point<dim> (edge_quadrature_points[q_point] (0),
+                                          0.5, 0.0);
+                          edge_quadrature_points_full_dim[3][q_point]
+                            = Point<dim> (edge_quadrature_points[q_point] (0),
+                                          1.0, 0.0);
+                        }
+                  
+                      Vector<double> system_rhs (system_matrix.m ());
+                      Vector<double> solution (system_rhs.size ());
+
+                      for (unsigned int dof = 0; dof < this->dofs_per_face;
+                           ++dof)
+                        {
+                                  // Set up the system matrix.
+                                  // This can be used for all
+                                  // edges.
+                             for (unsigned int q_point = 0;
+                                  q_point < n_edge_points; ++q_point)
+                               {
+                                     const double tmp
+                                       = 2.0 * edge_quadrature_points[q_point] (0)
+                                         - 1.0;
+                                     const double weight
+                                       = std::sqrt (2.0 * edge_quadrature.weight
+                                                          (q_point));
+
+                              for (unsigned int i = 0; i < deg; ++i)
+                                assembling_matrix (i, q_point)
+                                  = weight
+                                    * lobatto_polynomials_grad[i + 1].value
+                                      (tmp);
+                               }
+                     
+                          assembling_matrix.mTmult (system_matrix,
+                                                    assembling_matrix);
+                          system_matrix_inv.invert (system_matrix);
+                     
+                          for (unsigned int line = 0;
+                               line < GeometryInfo<dim - 1>::lines_per_cell;
+                               ++line)
+                            {
+                                  // Set up the right hand side.
+                              system_rhs = 0;
+                        
+                              for (unsigned int q_point = 0;
+                                   q_point < n_edge_points; ++q_point)
+                                {
+                                  const double right_hand_side_value
+                                    = std::sqrt (2.0 * edge_quadrature.weight
+                                                       (q_point))
+                                      * (this->shape_value_component
+                                         (this->face_to_cell_index (dof, 4),
+                                          edge_quadrature_points_full_dim[line][q_point],
+                                          1) - interpolation_matrix
+                                               (line * source_fe.degree, dof));
+                                  const double tmp
+                                    = 2.0 * edge_quadrature_points[q_point] (0)
+                                      - 1.0;
+                                 
+                                  for (unsigned int i = 0; i < deg; ++i)
+                                    system_rhs (i)
+                                      += right_hand_side_value
+                                         * lobatto_polynomials_grad[i + 1].value
+                                           (tmp);
+                                }
+
+                              system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                              for (unsigned int i = 0; i < solution.size ();
+                                   ++i)
+                                if (std::abs (solution (i)) > 1e-14)
+                                  interpolation_matrix
+                                  (line * source_fe.degree + i + 1, dof)
+                                    = solution (i);
+                            }
+
+                          assembling_matrix.reinit (deg * this->degree,
+                                                    n_face_points);
+                          system_rhs.reinit (assembling_matrix.m ());
+                          system_rhs = 0;
+
+                                  // Now we project the remaining
+                                  // part on the face shape
+                                  // functions. First on the
+                                  // horizontal ones, then on
+                                  // the vertical ones. 
+                          for (unsigned int q_point = 0;
+                               q_point < n_face_points; ++q_point)
+                            {
+                              const Point<dim> quadrature_point
+                                (2.0 * face_quadrature_points[q_point] (0)
+                                 - 1.0,
+                                 2.0 * face_quadrature_points[q_point] (1)
+                                 - 1.0, 0.0);
+                              double right_hand_side_value
+                                = this->shape_value_component
+                                  (this->face_to_cell_index (dof, 4),
+                                   Point<dim>
+                                   (face_quadrature_points[q_point] (0),
+                                    face_quadrature_points[q_point] (1), 0.0),
+                                   1);
+
+                              for (unsigned int i = 0; i < 2; ++i)
+                                for (unsigned int j = 0; j < source_fe.degree;
+                                     ++j)
+                                  right_hand_side_value
+                                    -= interpolation_matrix
+                                       (i * source_fe.degree + j, dof)
+                                       * source_fe.shape_value_component
+                                         (i * source_fe.degree + j,
+                                          quadrature_point, 1);
+                        
+                              right_hand_side_value
+                                *= 4.0 * face_quadrature.weight (q_point);
+                              
+                              const double weight
+                                = std::sqrt (4.0 * face_quadrature.weight
+                                                   (q_point));
+                        
+                              for (unsigned int i = 0; i <= deg; ++i)
+                                {
+                                  const double L_i
+                                    = legendre_polynomials[i].value
+                                      (quadrature_point (0));
+                                  const double tmp1 = weight * L_i;
+                                  const double tmp2 = right_hand_side_value
+                                                      * L_i;
+                           
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    {
+                                         const double l_j
+                                           = lobatto_polynomials[j + 2].value
+                                             (quadrature_point (1));
+                                         
+                                         assembling_matrix (i * deg + j, q_point)
+                                           = tmp1 * l_j;
+                                      system_rhs (i * deg + j) +=  tmp2 * l_j;
+                                    }
+                                }
+                            }
+
+                          system_matrix.reinit (assembling_matrix.m (),
+                                                assembling_matrix.m ());
+                          assembling_matrix.mTmult (system_matrix,
+                                                    assembling_matrix);
+                          system_matrix_inv.reinit (system_matrix.m (),
+                                                    system_matrix.m ());
+                          system_matrix_inv.invert (system_matrix);
+                          solution.reinit (system_matrix.m ());
+                          system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                          for (unsigned int i = 0; i <= deg; ++i)
+                            for (unsigned int j = 0; j < deg; ++j)
+                              if (std::abs (solution (i * deg + j)) > 1e-14)
+                                interpolation_matrix
+                                ((i + 4) * source_fe.degree + j - i, dof)
+                                  = solution (i * deg + j);
+                          
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                          system_rhs = 0;
+
+                          for (unsigned int q_point = 0;
+                               q_point < n_face_points; ++q_point)
+                            {
+                              const Point<dim> quadrature_point
+                                (2.0 * face_quadrature_points[q_point] (0)
+                                 - 1.0,
+                                 2.0 * face_quadrature_points[q_point] (1)
+                                 - 1.0, 0.0);
+                              double right_hand_side_value
+                                = this->shape_value_component
+                                  (this->face_to_cell_index (dof, 4),
+                                   Point<dim>
+                                   (face_quadrature_points[q_point] (0),
+                                    face_quadrature_points[q_point] (1), 0.0),
+                                   0);
+
+                              for (unsigned int i = 0; i < 2; ++i)
+                                for (unsigned int j = 0; j < source_fe.degree;
+                                     ++j)
+                                  right_hand_side_value
+                                    -= interpolation_matrix
+                                       ((i + 2) * source_fe.degree + j, dof)
+                                       * source_fe.shape_value_component
+                                         (i * source_fe.degree + j,
+                                          quadrature_point, 0);
+
+                              right_hand_side_value
+                                *= 4.0 * face_quadrature.weight (q_point);
+                        
+                              for (unsigned int i = 0; i <= deg; ++i)
+                                {
+                                  const double L_i
+                                    = legendre_polynomials[i].value
+                                      (quadrature_point (0));
+                                  const double tmp
+                                    = right_hand_side_value * L_i;
+                           
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    system_rhs (i * deg + j)
+                                      += tmp
+                                         * lobatto_polynomials[j + 2].value
+                                           (quadrature_point (1));
+                                }
+                            }
+
+                          system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the interpolation
+                                  // matrix only, if they are
+                                  // not too small.
+                          for (unsigned int i = 0; i <= deg; ++i)
+                            for (unsigned int j = 0; j < deg; ++j)
+                              if (std::abs (solution (i * deg + j)) > 1e-14)
+                                interpolation_matrix
+                                (i + (j + source_fe.degree + 3)
+                                 * source_fe.degree, dof)
+                                  = solution (i * deg + j);
+                        }
+                    }
+                  
+                  break;
+                }
+              
+              default:
+                Assert (false, ExcNotImplemented ());
+            }
           
-                                          // then copy over to target:
-         for (unsigned int q=0; q<n_q_points; ++q)
-           for (unsigned int d=0; d<dim; ++d)
-             data.shape_gradients[k*dim+d][q] = shape_grads2[q][d];
-       };
+          break;
+        }
+      
+      default:
+        Assert (false, ExcNotImplemented ());
     }
-
-  if (flags & update_hessians)
-    this->compute_2nd (mapping, cell, offset, mapping_data, fe_data, data);
 }
 
+#endif
 
-
-template <int dim, int spacedim>
-unsigned int
-FE_Nedelec<dim,spacedim>::n_base_elements () const
-{
-  return 1;
-}
-
-
-
-template <int dim, int spacedim>
-const FiniteElement<dim,spacedim> &
-FE_Nedelec<dim,spacedim>::base_element (const unsigned int index) const
-{
-  Assert (index==0, ExcIndexRange(index, 0, 1));
-  return *this;
+                   // Since this is a vector valued element,
+                   // we cannot interpolate a scalar function.
+template <int dim>
+void FE_Nedelec<dim>::interpolate (std::vector<double>&, const std::vector<double>&) const {
+   Assert(false, ExcNotImplemented ());
 }
 
 
-
-template <int dim, int spacedim>
-unsigned int
-FE_Nedelec<dim,spacedim>::element_multiplicity (const unsigned int index) const
+                   // Interpolate a function, which is given by
+                   // its values at the generalized support
+                   // points in the finite element space on the
+                   // reference cell.
+                   // This is done as usual by projection-based
+                   // interpolation.
+template <int dim>
+void
+FE_Nedelec<dim>::interpolate (std::vector<double>& local_dofs,
+                              const std::vector<Vector<double> >& values,
+                              unsigned int offset) const
 {
-  Assert (index==0, ExcIndexRange(index, 0, 1));
-  return 1;
+  Assert (values.size () == this->generalized_support_points.size (),
+          ExcDimensionMismatch (values.size (),
+                                this->generalized_support_points.size ()));
+  Assert (local_dofs.size () == this->dofs_per_cell,
+          ExcDimensionMismatch (local_dofs.size (),this->dofs_per_cell));
+  Assert (values[0].size () >= offset + this->n_components (),
+          ExcDimensionMismatch (values[0].size (),
+                                offset + this->n_components ()));
+  std::fill (local_dofs.begin (), local_dofs.end (), 0.);
+
+  if (offset < dim)
+    switch (dim)
+      {
+        case 2:
+          {
+            const QGauss<dim - 1> reference_edge_quadrature (this->degree);
+            const unsigned int& n_edge_points
+              = reference_edge_quadrature.size ();
+
+                                  // Let us begin with the
+                                  // interpolation part.
+            for (unsigned int i = 0; i < 2; ++i)
+              {
+                for (unsigned int q_point = 0; q_point < n_edge_points;
+                     ++q_point)
+                  local_dofs[i * this->degree]
+                    += reference_edge_quadrature.weight (q_point)
+                       * values[q_point + i * n_edge_points] (1);
+               
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                if (std::abs (local_dofs[i * this->degree]) < 1e-14)
+                  local_dofs[i * this->degree] = 0.0;
+              }
+
+            if (offset == 0)
+              for (unsigned int i = 0; i < 2; ++i)
+                {
+                  for (unsigned int q_point = 0; q_point < n_edge_points;
+                       ++q_point)
+                    local_dofs[(i + 2) * this->degree]
+                      += reference_edge_quadrature.weight (q_point)
+                         * values[q_point + (i + 2) * n_edge_points] (0);
+                  
+                  if (std::abs (local_dofs[(i + 2) * this->degree]) < 1e-14)
+                    local_dofs[(i + 2) * this->degree] = 0.0;
+                }
+
+                                  // If the degree is greater
+                                  // than 0, then we have still
+                                  // some higher order edge
+                                  // shape functions to
+                                  // consider.
+                                  // Here the projection part
+                                  // starts. The dof values
+                                  // are obtained by solving
+                                  // a linear system of
+                                  // equations.
+            if (deg > 0)
+              {
+                                         // We start with projection
+                                         // on the higher order edge
+                                         // shape function.
+                const std::vector<Polynomials::Polynomial<double> >&
+                  lobatto_polynomials
+                    = Polynomials::Lobatto::generate_complete_basis
+                      (this->degree);
+                const unsigned int
+                  line_coordinate[GeometryInfo<2>::lines_per_cell]
+                    = {1, 1, 0, 0};
+                std::vector<Polynomials::Polynomial<double> >
+                  lobatto_polynomials_grad (this->degree);
+
+                for (unsigned int i = 0; i < lobatto_polynomials_grad.size ();
+                     ++i)
+                  lobatto_polynomials_grad[i]
+                    = lobatto_polynomials[i + 1].derivative ();
+                
+                                  // Set up the system matrix.
+                                  // This can be used for all
+                                  // edges.
+                FullMatrix<double> system_matrix (deg, deg);
+
+                for (unsigned int i = 0; i < system_matrix.m (); ++i)
+                  for (unsigned int j = 0; j < system_matrix.n (); ++j)
+                    for (unsigned int q_point = 0; q_point < n_edge_points;
+                         ++q_point)
+                      system_matrix (i, j)
+                        += boundary_weights (q_point, j)
+                           * lobatto_polynomials_grad[i + 1].value
+                             (this->generalized_face_support_points[q_point]
+                              (1));
+
+                FullMatrix<double> system_matrix_inv (deg, deg);
+
+                system_matrix_inv.invert (system_matrix);
+                
+                Vector<double> system_rhs (system_matrix.m ());
+                Vector<double> solution (system_rhs.size ());
+
+                for (unsigned int line = 0;
+                     line < GeometryInfo<dim>::lines_per_cell; ++line)
+                  if ((line < 2) || (offset == 0))
+                    {
+                                  // Set up the right hand side.
+                      system_rhs = 0;
+                        
+                      for (unsigned int q_point = 0; q_point < n_edge_points;
+                           ++q_point)
+                        {
+                          const double tmp
+                            = values[line * n_edge_points + q_point]
+                              (line_coordinate[line])
+                              - local_dofs[line * this->degree]
+                              * this->shape_value_component
+                                (line * this->degree,
+                                 this->generalized_support_points[line
+                                                                  * n_edge_points
+                                                                  + q_point],
+                                 line_coordinate[line]);
+
+                          for (unsigned int i = 0; i < system_rhs.size ();
+                               ++i)
+                            system_rhs (i) += boundary_weights (q_point, i)
+                                              * tmp;
+                        }
+
+                      system_matrix_inv.vmult (solution, system_rhs);
+                        
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                      for (unsigned int i = 0; i < solution.size (); ++i)
+                        if (std::abs (solution (i)) > 1e-14)
+                          local_dofs[line * this->degree + i + 1]
+                            = solution (i);
+                    }
+
+                                  // Then we go on to the
+                                  // interior shape
+                                  // functions. Again we
+                                  // set up the system
+                                  // matrix and use it
+                                  // for both, the
+                                  // horizontal and the
+                                  // vertical, interior
+                                  // shape functions.
+                const QGauss<dim> reference_quadrature (this->degree);
+                const std::vector<Polynomials::Polynomial<double> >&
+                  legendre_polynomials
+                    = Polynomials::Legendre::generate_complete_basis (deg);
+                const unsigned int& n_interior_points
+                  = reference_quadrature.size ();
+
+                system_matrix.reinit (deg * this->degree, deg * this->degree);
+                system_matrix = 0;
+
+                for (unsigned int i = 0; i <= deg; ++i)
+                  for (unsigned int j = 0; j < deg; ++j)
+                    for (unsigned int k = 0; k <= deg; ++k)
+                      for (unsigned int l = 0; l < deg; ++l)
+                        for (unsigned int q_point = 0;
+                             q_point < n_interior_points; ++q_point)
+                          system_matrix (i * deg + j, k * deg + l)
+                            += reference_quadrature.weight (q_point)
+                               * legendre_polynomials[i].value
+                                 (this->generalized_support_points[q_point
+                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                   * n_edge_points]
+                                  (0))
+                               * lobatto_polynomials[j + 2].value
+                                 (this->generalized_support_points[q_point
+                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                   * n_edge_points]
+                                  (1))
+                               * lobatto_polynomials_grad[k].value
+                                 (this->generalized_support_points[q_point
+                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                   * n_edge_points]
+                                  (0))
+                               * lobatto_polynomials[l + 2].value
+                                 (this->generalized_support_points[q_point
+                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                   * n_edge_points]
+                                  (1));
+
+                system_matrix_inv.reinit (system_matrix.m (),
+                                          system_matrix.m ());
+                system_matrix_inv.invert (system_matrix);
+                solution.reinit (system_matrix_inv.m ());
+                system_rhs.reinit (system_matrix.m ());
+
+                if (offset == 0)
+                  {
+                                  // Set up the right hand side
+                                  // for the horizontal shape
+                                  // functions.
+                    system_rhs = 0;
+                    
+                    for (unsigned int q_point = 0;
+                         q_point < n_interior_points; ++q_point)
+                      {
+                        double tmp
+                          = values[q_point + GeometryInfo<dim>::lines_per_cell
+                                   * n_edge_points] (0);
+
+                        for (unsigned int i = 0; i < 2; ++i)
+                          for (unsigned int j = 0; j <= deg; ++j)
+                            tmp -= local_dofs[(i + 2) * this->degree + j]
+                                   * this->shape_value_component
+                                     ((i + 2) * this->degree + j,
+                                      this->generalized_support_points[q_point
+                                                                       + GeometryInfo<dim>::lines_per_cell
+                                                                       * n_edge_points],
+                                      0);
+
+                        for (unsigned int i = 0; i <= deg; ++i)
+                          for (unsigned int j = 0; j < deg; ++j)
+                            system_rhs (i * deg + j)
+                              += reference_quadrature.weight (q_point) * tmp
+                                 * lobatto_polynomials_grad[i].value
+                                   (this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points]
+                                    (0))
+                                 * lobatto_polynomials[j + 2].value
+                                   (this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points]
+                                    (1));
+                      }
+
+                    system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                    for (unsigned int i = 0; i <= deg; ++i)
+                      for (unsigned int j = 0; j < deg; ++j)
+                        if (std::abs (solution (i * deg + j)) > 1e-14)
+                           local_dofs[(i + GeometryInfo<dim>::lines_per_cell)
+                                      * deg + j
+                                      + GeometryInfo<dim>::lines_per_cell]
+                             = solution (i * deg + j);
+                  }
+
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                system_rhs = 0;
+
+                for (unsigned int q_point = 0; q_point < n_interior_points;
+                     ++q_point)
+                  {
+                    double tmp
+                      = values[q_point + GeometryInfo<dim>::lines_per_cell
+                               * n_edge_points] (1);
+
+                    for (unsigned int i = 0; i < 2; ++i)
+                      for (unsigned int j = 0; j <= deg; ++j)
+                        tmp -= local_dofs[i * this->degree + j]
+                               * this->shape_value_component
+                                 (i * this->degree + j,
+                                  this->generalized_support_points[q_point
+                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                   * n_edge_points],
+                                  1);
+
+                    for (unsigned i = 0; i <= deg; ++i)
+                      for (unsigned int j = 0; j < deg; ++j)
+                        system_rhs (i * deg + j)
+                          += reference_quadrature.weight (q_point) * tmp
+                             * lobatto_polynomials_grad[i].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points]
+                                (1))
+                             * lobatto_polynomials[j + 2].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points]
+                                (0));
+                  }
+
+                system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                for (unsigned int i = 0; i <= deg; ++i)
+                  for (unsigned int j = 0; j < deg; ++j)
+                    if (std::abs (solution (i * deg + j)) > 1e-14)
+                      local_dofs[i + (j + GeometryInfo<dim>::lines_per_cell
+                                      + deg) * this->degree]
+                        = solution (i * deg + j);
+              }
+
+            break;
+          }
+
+        case 3:
+          {
+            const QGauss<dim - 2>
+              reference_edge_quadrature (this->degree);
+            const unsigned int&
+              n_edge_points = reference_edge_quadrature.size ();
+
+                                  // Let us begin with the
+                                  // interpolation part.
+            for (unsigned int i = 0; i < 4; ++i)
+              {
+                for (unsigned int q_point = 0; q_point < n_edge_points;
+                     ++q_point)
+                  local_dofs[(i + 8) * this->degree]
+                    += reference_edge_quadrature.weight (q_point)
+                       * values[q_point + (i + 8) * n_edge_points] (2);
+               
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                if (std::abs (local_dofs[(i + 8) * this->degree]) < 1e-14)
+                  local_dofs[(i + 8) * this->degree] = 0.0;
+              }
+
+            if (offset < dim - 1)
+              {
+                for (unsigned int i = 0; i < 2; ++i)
+                  for (unsigned int j = 0; j < 2; ++j)
+                    {
+                      for (unsigned int q_point = 0; q_point < n_edge_points;
+                           ++q_point)
+                        local_dofs[(i + 4 * j) * this->degree]
+                          += reference_edge_quadrature.weight (q_point)
+                             * values[q_point + (i + 4 * j) * n_edge_points]
+                               (1);
+                     
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                      if (std::abs (local_dofs[(i + 4 * j) * this->degree])
+                            < 1e-14)
+                        local_dofs[(i + 4 * j) * this->degree] = 0.0;
+                    }
+
+                if (offset == 0)
+                  for (unsigned int i = 0; i < 2; ++i)
+                    for (unsigned int j = 0; j < 2; ++j)
+                      {
+                        for (unsigned int q_point = 0;
+                             q_point < n_edge_points; ++q_point)
+                          local_dofs[(i + 4 * j + 2) * this->degree]
+                            += reference_edge_quadrature.weight (q_point)
+                               * values[q_point + (i + 4 * j + 2)
+                                        * n_edge_points] (0);
+                        
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                        if (std::abs (local_dofs[(i + 4 * j + 2)
+                                                 * this->degree]) < 1e-14)
+                          local_dofs[(i + 4 * j + 2) * this->degree] = 0.0;
+                      }
+              }
+
+                                  // If the degree is greater
+                                  // than 0, then we have still
+                                  // some higher order shape
+                                  // functions to consider.
+                                  // Here the projection part
+                                  // starts. The dof values
+                                  // are obtained by solving
+                                  // a linear system of
+                                  // equations.
+            if (deg > 0)
+              {
+                                         // We start with projection
+                                         // on the higher order edge
+                                         // shape function.
+                const std::vector<Polynomials::Polynomial<double> >&
+                  lobatto_polynomials
+                    = Polynomials::Lobatto::generate_complete_basis
+                      (this->degree);
+                const unsigned int
+                  line_coordinate[GeometryInfo<3>::lines_per_cell]
+                    = {1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2};
+                FullMatrix<double> system_matrix (deg, deg);
+                FullMatrix<double> system_matrix_inv (deg, deg);
+                std::vector<Polynomials::Polynomial<double> >
+                  lobatto_polynomials_grad (this->degree);
+
+                for (unsigned int i = 0; i < lobatto_polynomials_grad.size ();
+                     ++i)
+                  lobatto_polynomials_grad[i]
+                    = lobatto_polynomials[i + 1].derivative ();
+                
+                Vector<double> system_rhs (system_matrix.m ());
+                Vector<double> solution (system_rhs.size ());
+
+                                  // Set up the system matrix.
+                                  // This can be used for all
+                                  // edges.
+                for (unsigned int i = 0; i < system_matrix.m (); ++i)
+                  for (unsigned int j = 0; j < system_matrix.n (); ++j)
+                    for (unsigned int q_point = 0; q_point < n_edge_points;
+                         ++q_point)
+                      system_matrix (i, j)
+                        += boundary_weights (q_point, j)
+                           * lobatto_polynomials_grad[i + 1].value
+                             (this->generalized_face_support_points[q_point]
+                              (1));
+
+                system_matrix_inv.invert (system_matrix);
+
+                for (unsigned int line = 0;
+                     line < GeometryInfo<dim>::lines_per_cell; ++line)
+                  {
+                                  // Set up the right hand side.
+                    system_rhs = 0;
+
+                    if ((((line == 0) || (line == 1) || (line == 4) ||
+                          (line == 5)) && (offset < dim - 1)) ||
+                        (((line == 2) || (line == 3) || (line == 6) ||
+                          (line == 7)) && (offset == 0)) || (line > 7))
+                      {
+                        for (unsigned int q_point = 0; q_point < n_edge_points;
+                             ++q_point)
+                          {
+                            double tmp
+                              = values[line * n_edge_points + q_point]
+                                (line_coordinate[line])
+                                - local_dofs[line * this->degree]
+                                * this->shape_value_component
+                                  (line * this->degree,
+                                   this->generalized_support_points[line
+                                                                    * this->degree
+                                                                    + q_point],
+                                   line_coordinate[line]);
+
+                            for (unsigned int i = 0; i < system_rhs.size ();
+                                 ++i)
+                              system_rhs (i)
+                                += boundary_weights (q_point, i) * tmp;
+                          }
+
+                        system_matrix_inv.vmult (solution, system_rhs);
+                           
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                        for (unsigned int i = 0; i < solution.size (); ++i)
+                          if (std::abs (solution (i)) > 1e-14)
+                            local_dofs[line * this->degree + i + 1]
+                              = solution (i);
+                      }
+                  }
+
+                                  // Then we go on to the
+                                  // face shape functions.
+                                  // Again we set up the
+                                  // system matrix and
+                                  // use it for both, the
+                                  // horizontal and the
+                                  // vertical, shape
+                                  // functions.
+                const std::vector<Polynomials::Polynomial<double> >&
+                  legendre_polynomials
+                    = Polynomials::Legendre::generate_complete_basis (deg);
+                const unsigned int
+                  n_face_points = n_edge_points * n_edge_points;
+
+                system_matrix.reinit (deg * this->degree, deg * this->degree);
+                system_matrix = 0;
+
+                for (unsigned int i = 0; i <= deg; ++i)
+                  for (unsigned int j = 0; j < deg; ++j)
+                    for (unsigned int k = 0; k <= deg; ++k)
+                      for (unsigned int l = 0; l < deg; ++l)
+                        for (unsigned int q_point = 0; q_point < n_face_points;
+                             ++q_point)
+                          system_matrix (i * deg + j, k * deg + l)
+                            += boundary_weights (q_point + n_edge_points,
+                                                 2 * (k * deg + l))
+                               * legendre_polynomials[i].value
+                                 (this->generalized_face_support_points[q_point
+                                                                        + 4
+                                                                        * n_edge_points]
+                                  (0))
+                               * lobatto_polynomials[j + 2].value
+                                 (this->generalized_face_support_points[q_point
+                                                                        + 4
+                                                                        * n_edge_points]
+                                  (1));
+
+                system_matrix_inv.reinit (system_matrix.m (),
+                                          system_matrix.n ());
+                system_matrix_inv.invert (system_matrix);
+                solution.reinit (system_matrix.m ());
+                system_rhs.reinit (system_matrix.m ());
+
+                for (unsigned int face = 0;
+                     face < GeometryInfo<dim>::faces_per_cell; ++face)
+                  {
+                    switch (face)
+                      {
+                        case 0:
+                          {
+                            if (offset < dim - 1)
+                              {
+                                  // Set up the right hand side
+                                  // for the horizontal shape
+                                  // functions.
+                               system_rhs = 0;
+                               
+                                for (unsigned int q_point = 0;
+                                     q_point < n_face_points; ++q_point)
+                                  {
+                                    double tmp
+                                      = values[q_point
+                                               + GeometryInfo<dim>::lines_per_cell
+                                               * n_edge_points] (1);
+
+                                    for (unsigned int i = 0; i < 2; ++i)
+                                      for (unsigned int j = 0; j <= deg; ++j)
+                                        tmp
+                                          -= local_dofs[4 * i * this->degree
+                                                        + j]
+                                             * this->shape_value_component
+                                               (4 * i * this->degree + j,
+                                                this->generalized_support_points[q_point
+                                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                                 * n_edge_points],
+                                                1);
+
+                                    for (unsigned int i = 0; i <= deg; ++i)
+                                      for (unsigned int j = 0; j < deg; ++j)
+                                        system_rhs (i * deg + j)
+                                         += boundary_weights
+                                            (q_point + n_edge_points,
+                                             2 * (i * deg + j)) * tmp;
+                                  }
+
+                                system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                                for (unsigned int i = 0; i <= deg; ++i)
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    if (std::abs (solution (i * deg + j))
+                                          > 1e-14)
+                                      local_dofs[(i
+                                                  + GeometryInfo<dim>::lines_per_cell)
+                                                 * deg + j
+                                                 + GeometryInfo<dim>::lines_per_cell]
+                                        = solution (i * deg + j);
+                              }
+                            
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                            system_rhs = 0;
+
+                            for (unsigned int q_point = 0;
+                                 q_point < n_face_points; ++q_point)
+                              {
+                                double tmp
+                                  = values[q_point
+                                           + GeometryInfo<dim>::lines_per_cell
+                                           * n_edge_points] (2);
+
+                                for (unsigned int i = 0; i < 2; ++i)
+                                  for (unsigned int j = 0; j <= deg; ++j)
+                                    tmp -= local_dofs[2 * (i + 4)
+                                                      * this->degree + j]
+                                           * this->shape_value_component
+                                             (2 * (i + 4) * this->degree + j,
+                                              this->generalized_support_points[q_point
+                                                                               + GeometryInfo<dim>::lines_per_cell
+                                                                               * n_edge_points],
+                                              2);
+
+                                for (unsigned i = 0; i <= deg; ++i)
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    system_rhs (i * deg + j)
+                                      += boundary_weights
+                                         (q_point + n_edge_points,
+                                          2 * (i * deg + j) + 1)
+                                         * tmp;
+                              }
+
+                            system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                            for (unsigned int i = 0; i <= deg; ++i)
+                              for (unsigned int j = 0; j < deg; ++j)
+                                if (std::abs (solution (i * deg + j)) > 1e-14)
+                                  local_dofs[i + (j + GeometryInfo<dim>::lines_per_cell
+                                                  + deg)
+                                             * this->degree]
+                                    = solution (i * deg + j);
+
+                            break;
+                          }
+
+                        case 1:
+                          {
+                            if (offset < dim - 1)
+                              {
+                                  // Set up the right hand side
+                                  // for the horizontal shape
+                                  // functions.
+                               system_rhs = 0;
+                               
+                                for (unsigned int q_point = 0;
+                                     q_point < n_face_points; ++q_point)
+                                  {
+                                    double tmp
+                                      = values[q_point
+                                               + GeometryInfo<dim>::lines_per_cell
+                                               * n_edge_points
+                                               + n_face_points] (1);
+
+                                    for (unsigned int i = 0; i < 2; ++i)
+                                      for (unsigned int j = 0; j <= deg; ++j)
+                                        tmp -= local_dofs[(4 * i + 1)
+                                                          * this->degree + j]
+                                               * this->shape_value_component
+                                                 ((4 * i + 1) * this->degree
+                                                  + j,
+                                                  this->generalized_support_points[q_point
+                                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                                   * n_edge_points
+                                                                                   + n_face_points],
+                                                  1);
+
+                                    for (unsigned int i = 0; i <= deg; ++i)
+                                      for (unsigned int j = 0; j < deg; ++j)
+                                        system_rhs (i * deg + j)
+                                          += boundary_weights
+                                             (q_point + n_edge_points,
+                                              2 * (i * deg + j)) * tmp;
+                                  }
+
+                                system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                                for (unsigned int i = 0; i <= deg; ++i)
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    if (std::abs (solution (i * deg + j))
+                                          > 1e-14)
+                                      local_dofs[(i + GeometryInfo<dim>::lines_per_cell
+                                                  + 2 * this->degree) * deg + j
+                                                  + GeometryInfo<dim>::lines_per_cell]
+                                        = solution (i * deg + j);
+                              }
+                            
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                            system_rhs = 0;
+
+                            for (unsigned int q_point = 0;
+                                 q_point < n_face_points; ++q_point)
+                              {
+                                double tmp
+                                  = values[q_point
+                                           + GeometryInfo<dim>::lines_per_cell
+                                           * n_edge_points + n_face_points]
+                                    (2);
+
+                                for (unsigned int i = 0; i < 2; ++i)
+                                  for (unsigned int j = 0; j <= deg; ++j)
+                                    tmp -= local_dofs[(2 * (i + 4) + 1)
+                                                      * this->degree + j]
+                                           * this->shape_value_component
+                                             ((2 * (i + 4) + 1) * this->degree
+                                              + j,
+                                              this->generalized_support_points[q_point
+                                                                               + GeometryInfo<dim>::lines_per_cell
+                                                                               * n_edge_points
+                                                                               + n_face_points],
+                                              2);
+
+                                for (unsigned i = 0; i <= deg; ++i)
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    system_rhs (i * deg + j)
+                                      += boundary_weights
+                                         (q_point + n_edge_points,
+                                          2 * (i * deg + j) + 1) * tmp;
+                              }
+
+                            system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                            for (unsigned int i = 0; i <= deg; ++i)
+                              for (unsigned int j = 0; j < deg; ++j)
+                                if (std::abs (solution (i * deg + j)) > 1e-14)
+                                  local_dofs[i + (j + GeometryInfo<dim>::lines_per_cell
+                                                  + 3 * deg)
+                                             * this->degree]
+                                    = solution (i * deg + j);
+
+                            break;
+                          }
+
+                        case 2:
+                          {
+                            if (offset == 0)
+                              {
+                                  // Set up the right hand side
+                                  // for the horizontal shape
+                                  // functions.
+                               system_rhs = 0;
+                               
+                                for (unsigned int q_point = 0;
+                                     q_point < n_face_points;
+                                     ++q_point)
+                                  {
+                                    double tmp
+                                      = values[q_point
+                                               + GeometryInfo<dim>::lines_per_cell
+                                               * n_edge_points
+                                               + 2 * n_face_points] (0);
+
+                                    for (unsigned int i = 0; i < 2; ++i)
+                                      for (unsigned int j = 0; j <= deg; ++j)
+                                        tmp -= local_dofs[(4 * i + 2)
+                                                          * this->degree + j]
+                                               * this->shape_value_component
+                                                 ((4 * i + 2) * this->degree
+                                                  + j,
+                                                  this->generalized_support_points[q_point
+                                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                                   * n_edge_points
+                                                                                   + 2
+                                                                                   * n_face_points],
+                                                  0);
+
+                                      for (unsigned int i = 0; i <= deg; ++i)
+                                        for (unsigned int j = 0; j < deg; ++j)
+                                          system_rhs (i * deg + j)
+                                            += boundary_weights
+                                               (q_point + n_edge_points,
+                                                2 * (i * deg + j) + 1) * tmp;
+                                  }
+
+                                system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                                for (unsigned int i = 0; i <= deg; ++i)
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    if (std::abs (solution (i * deg + j))
+                                          > 1e-14)
+                                      local_dofs[(i + GeometryInfo<dim>::lines_per_cell
+                                                  + 4 * this->degree) * deg
+                                                 + j
+                                                 + GeometryInfo<dim>::lines_per_cell]
+                                        = solution (i * deg + j);
+                              }
+
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                            system_rhs = 0;
+                            
+                            for (unsigned int q_point = 0;
+                                 q_point < n_face_points; ++q_point)
+                              {
+                                double tmp
+                                  = values[q_point
+                                           + GeometryInfo<dim>::lines_per_cell
+                                           * n_edge_points + 2 * n_face_points]
+                                    (2);
+
+                                for (unsigned int i = 0; i < 2; ++i)
+                                  for (unsigned int j = 0; j <= deg; ++j)
+                                    tmp -= local_dofs[(i + 8) * this->degree
+                                                      + j]
+                                           * this->shape_value_component
+                                             ((i + 8) * this->degree + j,
+                                              this->generalized_support_points[q_point
+                                                                               + GeometryInfo<dim>::lines_per_cell
+                                                                               * n_edge_points
+                                                                               + 2
+                                                                               * n_face_points],
+                                              2);
+
+                                for (unsigned i = 0; i <= deg; ++i)
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    system_rhs (i * deg + j)
+                                      += boundary_weights
+                                         (q_point + n_edge_points,
+                                          2 * (i * deg + j)) * tmp;
+                              }
+
+                            system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                            for (unsigned int i = 0; i <= deg; ++i)
+                              for (unsigned int j = 0; j < deg; ++j)
+                                if (std::abs (solution (i * deg + j)) > 1e-14)
+                                 local_dofs[i + (j + GeometryInfo<dim>::lines_per_cell
+                                                 + 5 * deg) * this->degree]
+                                   = solution (i * deg + j);
+
+                            break;
+                          }
+
+                        case 3:
+                          {
+                            if (offset == 0)
+                              {
+                                  // Set up the right hand side
+                                  // for the horizontal shape
+                                  // functions.
+                                system_rhs = 0;
+                                
+                                for (unsigned int q_point = 0;
+                                     q_point < n_face_points; ++q_point)
+                                  {
+                                    double tmp
+                                      = values[q_point
+                                               + GeometryInfo<dim>::lines_per_cell
+                                               * n_edge_points + 3
+                                               * n_face_points] (0);
+
+                                    for (unsigned int i = 0; i < 2; ++i)
+                                      for (unsigned int j = 0; j <= deg; ++j)
+                                        tmp -= local_dofs[(4 * i + 3)
+                                                          * this->degree + j]
+                                               * this->shape_value_component
+                                                 ((4 * i + 3) * this->degree
+                                                  + j,
+                                                  this->generalized_support_points[q_point
+                                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                                   * n_edge_points
+                                                                                   + 3
+                                                                                   * n_face_points],
+                                                  0);
+
+                                    for (unsigned int i = 0; i <= deg; ++i)
+                                      for (unsigned int j = 0; j < deg; ++j)
+                                        system_rhs (i * deg + j)
+                                          += boundary_weights
+                                             (q_point + n_edge_points,
+                                              2 * (i * deg + j) + 1) * tmp;
+                                  }
+
+                                system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                                for (unsigned int i = 0; i <= deg; ++i)
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    if (std::abs (solution (i * deg + j))
+                                          > 1e-14)
+                                      local_dofs[(i + GeometryInfo<dim>::lines_per_cell
+                                                  + 6 * this->degree) * deg + j
+                                                  + GeometryInfo<dim>::lines_per_cell]
+                                        = solution (i * deg + j);
+                              }
+                            
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                            system_rhs = 0;
+
+                            for (unsigned int q_point = 0;
+                                 q_point < n_face_points; ++q_point)
+                              {
+                                double tmp
+                                  = values[q_point
+                                           + GeometryInfo<dim>::lines_per_cell
+                                           * n_edge_points + 3 * n_face_points]
+                                    (2);
+
+                                for (unsigned int i = 0; i < 2; ++i)
+                                  for (unsigned int j = 0; j <= deg; ++j)
+                                    tmp -= local_dofs[(i + 10) * this->degree
+                                                      + j]
+                                           * this->shape_value_component
+                                             ((i + 10) * this->degree + j,
+                                              this->generalized_support_points[q_point
+                                                                               + GeometryInfo<dim>::lines_per_cell
+                                                                               * n_edge_points
+                                                                               + 3
+                                                                               * n_face_points],
+                                              2);
+
+                                for (unsigned i = 0; i <= deg; ++i)
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    system_rhs (i * deg + j)
+                                      += boundary_weights
+                                         (q_point + n_edge_points,
+                                          2 * (i * deg + j)) * tmp;
+                              }
+
+                            system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                            for (unsigned int i = 0; i <= deg; ++i)
+                              for (unsigned int j = 0; j < deg; ++j)
+                                if (std::abs (solution (i * deg + j)) > 1e-14)
+                                  local_dofs[i + (j + GeometryInfo<dim>::lines_per_cell
+                                                  + 7 * deg) * this->degree]
+                                    = solution (i * deg + j);
+
+                            break;
+                          }
+
+                        case 4:
+                          {
+                            if (offset < dim - 1)
+                              {
+                                  // Set up the right hand side
+                                  // for the horizontal shape
+                                  // functions.
+                                if (offset == 0)
+                                  {
+                                    system_rhs = 0;
+                                    
+                                    for (unsigned int q_point = 0;
+                                         q_point < n_face_points; ++q_point)
+                                      {
+                                        double tmp
+                                          = values[q_point
+                                                   + GeometryInfo<dim>::lines_per_cell
+                                                   * n_edge_points + 4
+                                                   * n_face_points] (0);
+
+                                        for (unsigned int i = 0; i < 2; ++i)
+                                          for (unsigned int j = 0; j <= deg; ++j)
+                                            tmp -= local_dofs[(i + 2)
+                                                              * this->degree
+                                                              + j]
+                                                   * this->shape_value_component
+                                                     ((i + 2) * this->degree
+                                                      + j,
+                                                      this->generalized_support_points[q_point
+                                                                                       + GeometryInfo<dim>::lines_per_cell
+                                                                                       * n_edge_points
+                                                                                       + 4
+                                                                                       * n_face_points],
+                                                      0);
+
+                                        for (unsigned int i = 0; i <= deg; ++i)
+                                          for (unsigned int j = 0; j < deg; ++j)
+                                            system_rhs (i * deg + j)
+                                              += boundary_weights
+                                                 (q_point + n_edge_points,
+                                                  2 * (i * deg + j)) * tmp;
+                                      }
+
+                                    system_matrix_inv.vmult
+                                      (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                                    for (unsigned int i = 0; i <= deg; ++i)
+                                      for (unsigned int j = 0; j < deg; ++j)
+                                        if (std::abs (solution (i * deg + j))
+                                              > 1e-14)
+                                          local_dofs[(i + GeometryInfo<dim>::lines_per_cell
+                                                      + 8 * this->degree) * deg
+                                                      + j
+                                                      + GeometryInfo<dim>::lines_per_cell]
+                                            = solution (i * deg + j);
+                                  }
+                                
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                                system_rhs = 0;
+
+                                for (unsigned int q_point = 0;
+                                     q_point < n_face_points; ++q_point)
+                                  {
+                                    double tmp
+                                      = values[q_point
+                                               + GeometryInfo<dim>::lines_per_cell
+                                               * n_edge_points + 4
+                                               * n_face_points] (1);
+
+                                    for (unsigned int i = 0; i < 2; ++i)
+                                      for (unsigned int j = 0; j <= deg; ++j)
+                                        tmp -= local_dofs[i * this->degree + j]
+                                               * this->shape_value_component
+                                                 (i * this->degree + j,
+                                                  this->generalized_support_points[q_point
+                                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                                   * n_edge_points
+                                                                                   + 4
+                                                                                   * n_face_points],
+                                                  1);
+
+                                    for (unsigned i = 0; i <= deg; ++i)
+                                      for (unsigned int j = 0; j < deg; ++j)
+                                        system_rhs (i * deg + j)
+                                          += boundary_weights
+                                             (q_point + n_edge_points,
+                                              2 * (i * deg + j) + 1) * tmp;
+                                  }
+
+                                system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                                for (unsigned int i = 0; i <= deg; ++i)
+                                  for (unsigned int j = 0; j < deg; ++j)
+                                    if (std::abs (solution (i * deg + j))
+                                          > 1e-14)
+                                      local_dofs[i + (j + GeometryInfo<dim>::lines_per_cell
+                                                      + 9 * deg)
+                                                 * this->degree]
+                                        = solution (i * deg + j);
+                              }
+
+                            break;
+                          }
+
+                        default:
+                          if (offset < dim - 1)
+                            {
+                                  // Set up the right hand side
+                                  // for the horizontal shape
+                                  // functions.
+                              if (offset == 0)
+                                {
+                                  system_rhs = 0;
+                                  
+                                  for (unsigned int q_point = 0;
+                                       q_point < n_face_points; ++q_point)
+                                    {
+                                      double tmp
+                                        = values[q_point
+                                                 + GeometryInfo<dim>::lines_per_cell
+                                                 * n_edge_points
+                                                 + 5 * n_face_points] (0);
+
+                                      for (unsigned int i = 0; i < 2; ++i)
+                                        for (unsigned int j = 0; j <= deg; ++j)
+                                          tmp -= local_dofs[(i + 6)
+                                                            * this->degree + j]
+                                                 * this->shape_value_component
+                                                   ((i + 6) * this->degree + j,
+                                                    this->generalized_support_points[q_point
+                                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                                     * n_edge_points
+                                                                                     + 5
+                                                                                     * n_face_points],
+                                                    0);
+
+                                      for (unsigned int i = 0; i <= deg; ++i)
+                                        for (unsigned int j = 0; j < deg; ++j)
+                                          system_rhs (i * deg + j)
+                                            += boundary_weights
+                                               (q_point + n_edge_points,
+                                                2 * (i * deg + j)) * tmp;
+                                    }
+
+                                  system_matrix_inv.vmult
+                                    (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                                  for (unsigned int i = 0; i <= deg; ++i)
+                                    for (unsigned int j = 0; j < deg; ++j)
+                                      if (std::abs (solution (i * deg + j))
+                                            > 1e-14)
+                                        local_dofs[(i + GeometryInfo<dim>::lines_per_cell
+                                                    + 10 * this->degree)
+                                                   * deg + j
+                                                   + GeometryInfo<dim>::lines_per_cell]
+                                          = solution (i * deg + j);
+                                }
+                              
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                              system_rhs = 0;
+
+                              for (unsigned int q_point = 0;
+                                   q_point < n_face_points; ++q_point)
+                                {
+                                  double tmp
+                                    = values[q_point
+                                             + GeometryInfo<dim>::lines_per_cell
+                                             * n_edge_points + 5
+                                             * n_face_points] (1);
+
+                                  for (unsigned int i = 0; i < 2; ++i)
+                                    for (unsigned int j = 0; j <= deg; ++j)
+                                      tmp -= local_dofs[(i + 4)
+                                                        * this->degree + j]
+                                             * this->shape_value_component
+                                               ((i + 4) * this->degree + j,
+                                                this->generalized_support_points[q_point
+                                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                                 * n_edge_points
+                                                                                 + 5
+                                                                                 * n_face_points],
+                                                1);
+
+                                  for (unsigned i = 0; i <= deg; ++i)
+                                    for (unsigned int j = 0; j < deg; ++j)
+                                      system_rhs (i * deg + j)
+                                        += boundary_weights
+                                           (q_point + n_edge_points,
+                                            2 * (i * deg + j) + 1) * tmp;
+                                }
+
+                              system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                              for (unsigned int i = 0; i <= deg; ++i)
+                                for (unsigned int j = 0; j < deg; ++j)
+                                  if (std::abs (solution (i * deg + j))
+                                        > 1e-14)
+                                    local_dofs[i + (j + GeometryInfo<dim>::lines_per_cell
+                                                    + 11 * deg) * this->degree]
+                                      = solution (i * deg + j);
+                            }
+                      }
+                  }
+
+                                  // Finally we project
+                                  // the remaining parts
+                                  // of the function on
+                                  // the interior shape
+                                  // functions.
+                const QGauss<dim> reference_quadrature (this->degree);
+                const unsigned int&
+                  n_interior_points = reference_quadrature.size ();
+
+                                  // We create the
+                                  // system matrix.
+                system_matrix.reinit (this->degree * deg * deg,
+                                      this->degree * deg * deg);
+                system_matrix = 0;
+
+                for (unsigned int i = 0; i <= deg; ++i)
+                  for (unsigned int j = 0; j < deg; ++j)
+                    for (unsigned int k = 0; k < deg; ++k)
+                      for (unsigned int l = 0; l <= deg; ++l)
+                        for (unsigned int m = 0; m < deg; ++m)
+                          for (unsigned int n = 0; n < deg; ++n)
+                            for (unsigned int q_point = 0;
+                                 q_point < n_interior_points; ++q_point)
+                              system_matrix ((i * deg + j) * deg + k,
+                                             (l * deg + m) * deg + n)
+                                += reference_quadrature.weight (q_point)
+                                   * legendre_polynomials[i].value
+                                     (this->generalized_support_points[q_point
+                                                                       + GeometryInfo<dim>::lines_per_cell
+                                                                       * n_edge_points
+                                                                       + GeometryInfo<dim>::faces_per_cell
+                                                                       * n_face_points]
+                                      (0)) * lobatto_polynomials[j + 2].value
+                                             (this->generalized_support_points[q_point
+                                                                               + GeometryInfo<dim>::lines_per_cell
+                                                                               * n_edge_points
+                                                                               + GeometryInfo<dim>::faces_per_cell
+                                                                               * n_face_points]
+                                              (1))
+                                           * lobatto_polynomials[k + 2].value
+                                             (this->generalized_support_points[q_point
+                                                                               + GeometryInfo<dim>::lines_per_cell
+                                                                               * n_edge_points
+                                                                               + GeometryInfo<dim>::faces_per_cell
+                                                                               * n_face_points]
+                                              (2))
+                                           * lobatto_polynomials_grad[l].value
+                                             (this->generalized_support_points[q_point
+                                                                               + GeometryInfo<dim>::lines_per_cell
+                                                                               * n_edge_points
+                                                                               + GeometryInfo<dim>::faces_per_cell
+                                                                               * n_face_points]
+                                              (0))
+                                           * lobatto_polynomials[m + 2].value
+                                             (this->generalized_support_points[q_point
+                                                                               + GeometryInfo<dim>::lines_per_cell
+                                                                               * n_edge_points
+                                                                               + GeometryInfo<dim>::faces_per_cell
+                                                                               * n_face_points]
+                                              (1))
+                                           * lobatto_polynomials[n + 2].value
+                                             (this->generalized_support_points[q_point
+                                                                               + GeometryInfo<dim>::lines_per_cell
+                                                                               * n_edge_points
+                                                                               + GeometryInfo<dim>::faces_per_cell
+                                                                               * n_face_points]
+                                              (2));
+
+                system_matrix_inv.reinit (system_matrix.m (),
+                                          system_matrix.m ());
+                system_matrix_inv.invert (system_matrix);
+                system_rhs.reinit (system_matrix_inv.m ());
+                solution.reinit (system_matrix.m ());
+
+                if (offset < dim - 1)
+                  {
+                    if (offset == 0)
+                      {
+                                  // Set up the right hand side.
+                        system_rhs = 0;
+                        
+                        for (unsigned int q_point = 0;
+                             q_point < n_interior_points; ++q_point)
+                          {
+                            double tmp
+                              = values[q_point
+                                       + GeometryInfo<dim>::lines_per_cell
+                                       * n_edge_points
+                                       + GeometryInfo<dim>::faces_per_cell
+                                       * n_face_points] (0);
+
+                            for (unsigned int i = 0; i <= deg; ++i)
+                              {
+                                for (unsigned int j = 0; j < 2; ++j)
+                                  for (unsigned int k = 0; k < 2; ++k)
+                                    tmp -= local_dofs[i + (j + 4 * k + 2)
+                                                      * this->degree]
+                                           * this->shape_value_component
+                                             (i + (j + 4 * k + 2)
+                                              * this->degree,
+                                              this->generalized_support_points[q_point
+                                                                               + GeometryInfo<dim>::lines_per_cell
+                                                                               * n_edge_points
+                                                                               + GeometryInfo<dim>::faces_per_cell
+                                                                               * n_face_points],
+                                              0);
+
+                                for (unsigned int j = 0; j < deg; ++j)
+                                  for (unsigned int k = 0; k < 4; ++k)
+                                    tmp -= local_dofs[(i + 2 * (k + 2)
+                                                       * this->degree
+                                                       + GeometryInfo<dim>::lines_per_cell)
+                                                      * deg + j
+                                                      + GeometryInfo<dim>::lines_per_cell]
+                                           * this->shape_value_component
+                                             ((i + 2 * (k + 2) * this->degree
+                                               + GeometryInfo<dim>::lines_per_cell)
+                                              * deg + j
+                                              + GeometryInfo<dim>::lines_per_cell,
+                                              this->generalized_support_points[q_point
+                                                                               + GeometryInfo<dim>::lines_per_cell
+                                                                               * n_edge_points
+                                                                               + GeometryInfo<dim>::faces_per_cell
+                                                                               * n_face_points],
+                                              0);
+                              }
+
+                            for (unsigned int i = 0; i <= deg; ++i)
+                              for (unsigned int j = 0; j < deg; ++j)
+                                for (unsigned int k = 0; k < deg; ++k)
+                                  system_rhs ((i * deg + j) * deg + k)
+                                    += reference_quadrature.weight (q_point)
+                                       * tmp
+                                       * lobatto_polynomials_grad[i].value
+                                         (this->generalized_support_points[q_point
+                                                                           + GeometryInfo<dim>::lines_per_cell
+                                                                           * n_edge_points
+                                                                           + GeometryInfo<dim>::faces_per_cell
+                                                                           * n_face_points]
+                                          (0))
+                                         * lobatto_polynomials[j + 2].value
+                                           (this->generalized_support_points[q_point
+                                                                             + GeometryInfo<dim>::lines_per_cell
+                                                                             * n_edge_points
+                                                                             + GeometryInfo<dim>::faces_per_cell
+                                                                             * n_face_points]
+                                          (1))
+                                         * lobatto_polynomials[k + 2].value
+                                           (this->generalized_support_points[q_point
+                                                                             + GeometryInfo<dim>::lines_per_cell
+                                                                             * n_edge_points
+                                                                             + GeometryInfo<dim>::faces_per_cell
+                                                                             * n_face_points]
+                                          (2));
+                          }
+
+                        system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                        for (unsigned int i = 0; i <= deg; ++i)
+                          for (unsigned int j = 0; j < deg; ++j)
+                            for (unsigned int k = 0; k < deg; ++k)
+                              if (std::abs (solution ((i * deg + j) * deg + k))
+                                    > 1e-14)
+                                local_dofs[((i + 2
+                                             * GeometryInfo<dim>::faces_per_cell)
+                                            * deg + j
+                                            + GeometryInfo<dim>::lines_per_cell
+                                            + 2
+                                            * GeometryInfo<dim>::faces_per_cell)
+                                           * deg + k
+                                           + GeometryInfo<dim>::lines_per_cell]
+                                = solution ((i * deg + j) * deg + k);
+                      }
+                    
+                                  // Set up the right hand side.
+                    system_rhs = 0;
+
+                    for (unsigned int q_point = 0; q_point < n_interior_points;
+                         ++q_point)
+                      {
+                        double tmp
+                          = values[q_point + GeometryInfo<dim>::lines_per_cell
+                                   * n_edge_points
+                                   + GeometryInfo<dim>::faces_per_cell
+                                   * n_face_points] (1);
+
+                        for (unsigned int i = 0; i <= deg; ++i)
+                          for (unsigned int j = 0; j < 2; ++j)
+                            {
+                              for (unsigned int k = 0; k < 2; ++k)
+                                tmp -= local_dofs[i + (4 * j + k)
+                                                  * this->degree]
+                                       * this->shape_value_component
+                                         (i + (4 * j + k) * this->degree,
+                                          this->generalized_support_points[q_point
+                                                                           + GeometryInfo<dim>::lines_per_cell
+                                                                           * n_edge_points
+                                                                           + GeometryInfo<dim>::faces_per_cell
+                                                                           * n_face_points],
+                                          1);
+
+                              for (unsigned int k = 0; k < deg; ++k)
+                                tmp -= local_dofs[(i + 2 * j * this->degree
+                                                   + GeometryInfo<dim>::lines_per_cell)
+                                                  * deg + k
+                                                  + GeometryInfo<dim>::lines_per_cell]
+                                       * this->shape_value_component
+                                         ((i + 2 * j * this->degree
+                                           + GeometryInfo<dim>::lines_per_cell)
+                                          * deg + k
+                                          + GeometryInfo<dim>::lines_per_cell,
+                                          this->generalized_support_points[q_point
+                                                                           + GeometryInfo<dim>::lines_per_cell
+                                                                           * n_edge_points
+                                                                           + GeometryInfo<dim>::faces_per_cell
+                                                                           * n_face_points],
+                                          1)
+                                       + local_dofs[i + ((2 * j + 9) * deg + k
+                                                    + GeometryInfo<dim>::lines_per_cell)
+                                                    * this->degree]
+                                       * this->shape_value_component
+                                         (i + ((2 * j + 9) * deg + k
+                                          + GeometryInfo<dim>::lines_per_cell)
+                                          * this->degree,
+                                          this->generalized_support_points[q_point
+                                                                           + GeometryInfo<dim>::lines_per_cell
+                                                                           * n_edge_points
+                                                                           + GeometryInfo<dim>::faces_per_cell
+                                                                           * n_face_points],
+                                          1);
+                            }
+
+                        for (unsigned int i = 0; i <= deg; ++i)
+                          for (unsigned int j = 0; j < deg; ++j)
+                            for (unsigned int k = 0; k < deg; ++k)
+                              system_rhs ((i * deg + j) * deg + k)
+                                += reference_quadrature.weight (q_point) * tmp
+                                   * lobatto_polynomials_grad[i].value
+                                     (this->generalized_support_points[q_point
+                                                                       + GeometryInfo<dim>::lines_per_cell
+                                                                       * n_edge_points
+                                                                       + GeometryInfo<dim>::faces_per_cell
+                                                                       * n_face_points]
+                                      (1))
+                                   * lobatto_polynomials[j + 2].value
+                                     (this->generalized_support_points[q_point
+                                                                       + GeometryInfo<dim>::lines_per_cell
+                                                                       * n_edge_points
+                                                                       + GeometryInfo<dim>::faces_per_cell
+                                                                       * n_face_points]
+                                      (0))
+                                   * lobatto_polynomials[k + 2].value
+                                     (this->generalized_support_points[q_point
+                                                                       + GeometryInfo<dim>::lines_per_cell
+                                                                       * n_edge_points
+                                                                       + GeometryInfo<dim>::faces_per_cell
+                                                                       * n_face_points]
+                                      (2));
+                      }
+
+                    system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                    for (unsigned int i = 0; i <= deg; ++i)
+                      for (unsigned int j = 0; j < deg; ++j)
+                        for (unsigned int k = 0; k < deg; ++k)
+                          if (std::abs (solution ((i * deg + j) * deg + k))
+                                > 1e-14)
+                            local_dofs[((i + this->degree + 2
+                                         * GeometryInfo<dim>::faces_per_cell)
+                                        * deg + j
+                                        + GeometryInfo<dim>::lines_per_cell + 2
+                                        * GeometryInfo<dim>::faces_per_cell)
+                                       * deg + k
+                                       + GeometryInfo<dim>::lines_per_cell]
+                              = solution ((i * deg + j) * deg + k);
+                  }
+                
+                                  // Set up the right hand side.
+                system_rhs = 0;
+
+                for (unsigned int q_point = 0; q_point < n_interior_points;
+                     ++q_point)
+                  {
+                    double tmp
+                      = values[q_point + GeometryInfo<dim>::lines_per_cell
+                               * n_edge_points
+                               + GeometryInfo<dim>::faces_per_cell
+                               * n_face_points] (2);
+
+                    for (unsigned int i = 0; i <= deg; ++i)
+                      for (unsigned int j = 0; j < 4; ++j)
+                        {
+                          tmp -= local_dofs[i + (j + 8) * this->degree]
+                                 * this->shape_value_component
+                                   (i + (j + 8) * this->degree,
+                                    this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points],
+                                    2);
+
+                          for (unsigned int k = 0; k < deg; ++k)
+                            tmp -= local_dofs[i + ((2 * j + 1) * deg + k
+                                                   + GeometryInfo<dim>::lines_per_cell)
+                                              * this->degree]
+                                   * this->shape_value_component
+                                     (i + ((2 * j + 1) * deg + k
+                                           + GeometryInfo<dim>::lines_per_cell)
+                                      * this->degree,
+                                      this->generalized_support_points[q_point
+                                                                       + GeometryInfo<dim>::lines_per_cell
+                                                                       * n_edge_points
+                                                                       + GeometryInfo<dim>::faces_per_cell
+                                                                       * n_face_points],
+                                      2);
+                        }
+
+                    for (unsigned int i = 0; i <= deg; ++i)
+                      for (unsigned int j = 0; j < deg; ++j)
+                        for (unsigned int k = 0; k < deg; ++k)
+                          system_rhs ((i * deg + j) * deg + k)
+                            += reference_quadrature.weight (q_point) * tmp
+                               * lobatto_polynomials_grad[i].value
+                                 (this->generalized_support_points[q_point
+                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                   * n_edge_points
+                                                                   + GeometryInfo<dim>::faces_per_cell
+                                                                   * n_face_points]
+                                  (2))
+                               * lobatto_polynomials[j + 2].value
+                                 (this->generalized_support_points[q_point
+                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                   * n_edge_points
+                                                                   + GeometryInfo<dim>::faces_per_cell
+                                                                   * n_face_points]
+                                  (0))
+                               * lobatto_polynomials[k + 2].value
+                                 (this->generalized_support_points[q_point
+                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                   * n_edge_points
+                                                                   + GeometryInfo<dim>::faces_per_cell
+                                                                   * n_face_points]
+                                  (1));
+                  }
+
+                system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                for (unsigned int i = 0; i <= deg; ++i)
+                  for (unsigned int j = 0; j < deg; ++j)
+                    for (unsigned int k = 0; k < deg; ++k)
+                      if (std::abs (solution ((i * deg + j) * deg + k))
+                            > 1e-14)
+                        local_dofs[i + ((j + 2
+                                         * (deg + GeometryInfo<dim>::faces_per_cell))
+                                        * deg + k
+                                        + GeometryInfo<dim>::lines_per_cell)
+                                   * this->degree]
+                          = solution ((i * deg + j) * deg + k);
+              }
+            
+            break;
+          }
+        
+        default:
+          Assert (false, ExcNotImplemented ());
+      }
 }
 
 
-
-template <int dim, int spacedim>
-bool
-FE_Nedelec<dim,spacedim>::has_support_on_face (const unsigned int shape_index,
-                                     const unsigned int face_index) const
+                   // Interpolate a function, which is given by
+                   // its values at the generalized support
+                   // points in the finite element space on the
+                   // reference cell.
+                   // This is done as usual by projection-based
+                   // interpolation.
+template <int dim>
+void
+FE_Nedelec<dim>::interpolate (std::vector<double>& local_dofs,
+                              const VectorSlice<const std::vector<std::vector<double> > >& values)
+const
 {
-  Assert (shape_index < this->dofs_per_cell,
-         ExcIndexRange (shape_index, 0, this->dofs_per_cell));
-  Assert (face_index < GeometryInfo<dim>::faces_per_cell,
-         ExcIndexRange (face_index, 0, GeometryInfo<dim>::faces_per_cell));
+  Assert (values.size () == this->n_components (),
+          ExcDimensionMismatch (values.size (), this->n_components ()));
+  Assert (values[0].size () == this->generalized_support_points.size (),
+          ExcDimensionMismatch (values[0].size (),
+                                this->generalized_support_points.size ()));
+  Assert (local_dofs.size () == this->dofs_per_cell,
+          ExcDimensionMismatch (local_dofs.size (), this->dofs_per_cell));
+  std::fill (local_dofs.begin (), local_dofs.end (), 0.0);
 
-  switch (degree)
+  switch (dim)
     {
-      case 1:
-      {
-        switch (dim)
-          {
-            case 2:
+      case 2:
+        {
+                                  // Let us begin with the
+                                  // interpolation part.
+          const QGauss<dim - 1> reference_edge_quadrature (this->degree);
+          const unsigned int&
+            n_edge_points = reference_edge_quadrature.size ();
+
+          for (unsigned int i = 0; i < 2; ++i)
+            for (unsigned int j = 0; j < 2; ++j)
+              {
+                for (unsigned int q_point = 0; q_point < n_edge_points;
+                     ++q_point)
+                  local_dofs[(i + 2 * j) * this->degree]
+                    += reference_edge_quadrature.weight (q_point)
+                       * values[1 - j][q_point + (i + 2 * j) * n_edge_points];
+               
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                if (std::abs (local_dofs[(i + 2 * j) * this->degree]) < 1e-14)
+                  local_dofs[(i + 2 * j) * this->degree] = 0.0;
+              }
+
+                                  // If the degree is greater
+                                  // than 0, then we have still
+                                  // some higher order edge
+                                  // shape functions to
+                                  // consider.
+                                  // Here the projection part
+                                  // starts. The dof values
+                                  // are obtained by solving
+                                  // a linear system of
+                                  // equations.
+          if (deg > 0)
             {
-                                               // only on the one
-                                               // non-adjacent face
-                                               // are the values
-                                               // actually zero. list
-                                               // these in a table
+                                         // We start with projection
+                                         // on the higher order edge
+                                         // shape function.
+              const std::vector<Polynomials::Polynomial<double> >&
+                lobatto_polynomials
+                  = Polynomials::Lobatto::generate_complete_basis
+                    (this->degree);
+              FullMatrix<double> system_matrix (deg, deg);
+              std::vector<Polynomials::Polynomial<double> >
+                lobatto_polynomials_grad (this->degree);
+              
+              for (unsigned int i = 0; i < lobatto_polynomials_grad.size ();
+                   ++i)
+                lobatto_polynomials_grad[i]
+                  = lobatto_polynomials[i + 1].derivative ();
+
+                                  // Set up the system matrix.
+                                  // This can be used for all
+                                  // edges.
+              for (unsigned int i = 0; i < system_matrix.m (); ++i)
+                for (unsigned int j = 0; j < system_matrix.n (); ++j)
+                  for (unsigned int q_point = 0; q_point < n_edge_points;
+                       ++q_point)
+                     system_matrix (i, j)
+                       += boundary_weights (q_point, j)
+                          * lobatto_polynomials_grad[i + 1].value
+                            (this->generalized_face_support_points[q_point]
+                             (1));
+
+              FullMatrix<double> system_matrix_inv (deg, deg);
+              
+              system_matrix_inv.invert (system_matrix);
+              
               const unsigned int
-                opposite_faces[GeometryInfo<2>::faces_per_cell]
-                = { 1, 0, 3, 2};
+                line_coordinate[GeometryInfo<2>::lines_per_cell]
+                  = {1, 1, 0, 0};
+              Vector<double> system_rhs (system_matrix.m ());
+              Vector<double> solution (system_rhs.size ());
+
+              for (unsigned int line = 0;
+                   line < GeometryInfo<dim>::lines_per_cell; ++line)
+                {
+                                  // Set up the right hand side.
+                  system_rhs = 0;
+
+                  for (unsigned int q_point = 0; q_point < n_edge_points;
+                       ++q_point)
+                    {
+                      const double tmp
+                        = values[line_coordinate[line]][line * n_edge_points
+                                                        + q_point]
+                          - local_dofs[line * this->degree]
+                          * this->shape_value_component
+                            (line * this->degree,
+                             this->generalized_support_points[line
+                                                              * n_edge_points
+                                                              + q_point],
+                             line_coordinate[line]);
+
+                      for (unsigned int i = 0; i < system_rhs.size (); ++i)
+                        system_rhs (i) += boundary_weights (q_point, i) * tmp;
+                    }
+
+                  system_matrix_inv.vmult (solution, system_rhs);
+               
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                  for (unsigned int i = 0; i < solution.size (); ++i)
+                    if (std::abs (solution (i)) > 1e-14)
+                      local_dofs[line * this->degree + i + 1] = solution (i);
+                }
+
+                                  // Then we go on to the
+                                  // interior shape
+                                  // functions. Again we
+                                  // set up the system
+                                  // matrix and use it
+                                  // for both, the
+                                  // horizontal and the
+                                  // vertical, interior
+                                  // shape functions.
+              const QGauss<dim> reference_quadrature (this->degree);
+              const unsigned int&
+                n_interior_points = reference_quadrature.size ();
+              const std::vector<Polynomials::Polynomial<double> >&
+                legendre_polynomials
+                  = Polynomials::Legendre::generate_complete_basis (deg);
               
-              return (face_index != opposite_faces[shape_index]);
-            };
-            
-            case 3:
+              system_matrix.reinit (deg * this->degree, deg * this->degree);
+              system_matrix = 0;
+
+              for (unsigned int i = 0; i <= deg; ++i)
+                for (unsigned int j = 0; j < deg; ++j)
+                  for (unsigned int k = 0; k <= deg; ++k)
+                    for (unsigned int l = 0; l < deg; ++l)
+                      for (unsigned int q_point = 0;
+                           q_point < n_interior_points; ++q_point)
+                        system_matrix (i * deg + j, k * deg + l)
+                          += reference_quadrature.weight (q_point)
+                             * legendre_polynomials[i].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points]
+                                (0))
+                             * lobatto_polynomials[j + 2].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points]
+                                (1))
+                             * lobatto_polynomials_grad[k].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points]
+                                (0))
+                             * lobatto_polynomials[l + 2].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points]
+                                (1));
+
+              system_matrix_inv.reinit (system_matrix.m (),
+                                        system_matrix.m ());
+              system_matrix_inv.invert (system_matrix);
+                                  // Set up the right hand side
+                                  // for the horizontal shape
+                                  // functions.
+              system_rhs.reinit (system_matrix_inv.m ());
+              system_rhs = 0;
+
+              for (unsigned int q_point = 0; q_point < n_interior_points;
+                   ++q_point)
+                {
+                  double tmp
+                    = values[0][q_point + GeometryInfo<dim>::lines_per_cell
+                                * n_edge_points];
+
+                  for (unsigned int i = 0; i < 2; ++i)
+                    for (unsigned int j = 0; j <= deg; ++j)
+                      tmp -= local_dofs[(i + 2) * this->degree + j]
+                             * this->shape_value_component
+                               ((i + 2) * this->degree + j,
+                                this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points],
+                                0);
+
+                  for (unsigned int i = 0; i <= deg; ++i)
+                    for (unsigned int j = 0; j < deg; ++j)
+                      system_rhs (i * deg + j)
+                        += reference_quadrature.weight (q_point) * tmp
+                           * lobatto_polynomials_grad[i].value
+                             (this->generalized_support_points[q_point
+                                                               + GeometryInfo<dim>::lines_per_cell
+                                                               * n_edge_points]
+                              (0))
+                           * lobatto_polynomials[j + 2].value
+                             (this->generalized_support_points[q_point
+                                                               + GeometryInfo<dim>::lines_per_cell
+                                                               * n_edge_points]
+                              (1));
+                }
+
+              solution.reinit (system_matrix.m ());
+              system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+              for (unsigned int i = 0; i <= deg; ++i)
+                for (unsigned int j = 0; j < deg; ++j)
+                  if (std::abs (solution (i * deg + j)) > 1e-14)
+                     local_dofs[(i + GeometryInfo<dim>::lines_per_cell) * deg
+                                + j + GeometryInfo<dim>::lines_per_cell]
+                       = solution (i * deg + j);
+
+              system_rhs = 0;
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+
+              for (unsigned int q_point = 0; q_point < n_interior_points;
+                   ++q_point)
+                {
+                  double tmp
+                    = values[1][q_point + GeometryInfo<dim>::lines_per_cell
+                                * n_edge_points];
+
+                  for (unsigned int i = 0; i < 2; ++i)
+                    for (unsigned int j = 0; j <= deg; ++j)
+                      tmp -= local_dofs[i * this->degree + j]
+                             * this->shape_value_component
+                               (i * this->degree + j,
+                                this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points],
+                                1);
+
+                  for (unsigned i = 0; i <= deg; ++i)
+                    for (unsigned int j = 0; j < deg; ++j)
+                      system_rhs (i * deg + j)
+                        += reference_quadrature.weight (q_point) * tmp
+                           * lobatto_polynomials_grad[i].value
+                             (this->generalized_support_points[q_point
+                                                               + GeometryInfo<dim>::lines_per_cell
+                                                               * n_edge_points]
+                              (1))
+                           * lobatto_polynomials[j + 2].value
+                             (this->generalized_support_points[q_point
+                                                               + GeometryInfo<dim>::lines_per_cell
+                                                               * n_edge_points]
+                              (0));
+                }
+
+              system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+              for (unsigned int i = 0; i <= deg; ++i)
+                for (unsigned int j = 0; j < deg; ++j)
+                  if (std::abs (solution (i * deg + j)) > 1e-14)
+                     local_dofs[i + (j + GeometryInfo<dim>::lines_per_cell
+                                     + deg) * this->degree]
+                       = solution (i * deg + j);
+            }
+
+          break;
+        }
+
+      case 3:
+        {
+                                  // Let us begin with the
+                                  // interpolation part.
+          const QGauss<dim - 2> reference_edge_quadrature (this->degree);
+          const unsigned int&
+            n_edge_points = reference_edge_quadrature.size ();
+
+          for (unsigned int q_point = 0; q_point < n_edge_points; ++q_point)
             {
-                                               // the shape functions
-                                               // are zero on the two
-                                               // faces opposite the
-                                               // two faces adjacent
-                                               // to the line the
-                                               // shape function is
-                                               // defined on
+              for (unsigned int i = 0; i < 4; ++i)
+                local_dofs[(i + 8) * this->degree]
+                  += reference_edge_quadrature.weight (q_point)
+                     * values[2][q_point + (i + 8) * n_edge_points];
+
+              for (unsigned int i = 0; i < 2; ++i)
+                for (unsigned int j = 0; j < 2; ++j)
+                  for (unsigned int k = 0; k < 2; ++k)
+                    local_dofs[(i + 2 * (2 * j + k)) * this->degree]
+                      += reference_edge_quadrature.weight (q_point)
+                         * values[1 - k][q_point + (i + 2 * (2 * j + k))
+                                         * n_edge_points];
+            }
+         
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+          for (unsigned int i = 0; i < 4; ++i)
+            if (std::abs (local_dofs[(i + 8) * this->degree]) < 1e-14)
+              local_dofs[(i + 8) * this->degree] = 0.0;
+         
+          for (unsigned int i = 0; i < 2; ++i)
+            for (unsigned int j = 0; j < 2; ++j)
+              for (unsigned int k = 0; k < 2; ++k)
+                if (std::abs (local_dofs[(i + 2 * (2 * j + k)) * this->degree])
+                      < 1e-14)
+                  local_dofs[(i + 2 * (2 * j + k)) * this->degree] = 0.0;
+
+                                  // If the degree is greater
+                                  // than 0, then we have still
+                                  // some higher order shape
+                                  // functions to consider.
+                                  // Here the projection part
+                                  // starts. The dof values
+                                  // are obtained by solving
+                                  // a linear system of
+                                  // equations.
+          if (deg > 0)
+            {
+                                         // We start with projection
+                                         // on the higher order edge
+                                         // shape function.
+              const std::vector<Polynomials::Polynomial<double> >&
+                lobatto_polynomials
+                  = Polynomials::Lobatto::generate_complete_basis
+                    (this->degree);
+              FullMatrix<double> system_matrix (deg, deg);
+              std::vector<Polynomials::Polynomial<double> >
+                lobatto_polynomials_grad (this->degree);
+              
+              for (unsigned int i = 0; i < lobatto_polynomials_grad.size ();
+                   ++i)
+                lobatto_polynomials_grad[i]
+                  = lobatto_polynomials[i + 1].derivative ();
+              
+                                  // Set up the system matrix.
+                                  // This can be used for all
+                                  // edges.
+              for (unsigned int i = 0; i < system_matrix.m (); ++i)
+                for (unsigned int j = 0; j < system_matrix.n (); ++j)
+                  for (unsigned int q_point = 0; q_point < n_edge_points;
+                       ++q_point)
+                    system_matrix (i, j)
+                      += boundary_weights (q_point, j)
+                         * lobatto_polynomials_grad[i + 1].value
+                           (this->generalized_face_support_points[q_point]
+                            (1));
+
+              FullMatrix<double> system_matrix_inv (deg, deg);
+              
+              system_matrix_inv.invert (system_matrix);
+
               const unsigned int
-                opposite_faces[GeometryInfo<3>::lines_per_cell][2]
-                = { {1,5}, {0,5}, {3,5}, {2,5},
-                   {1,4}, {0,4}, {3,4}, {2,4},
-                   {1,3}, {0,3}, {1,2}, {0,2}};
+                line_coordinate[GeometryInfo<3>::lines_per_cell]
+                  = {1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2};
+              Vector<double> system_rhs (system_matrix.m ());
+              Vector<double> solution (system_rhs.size ());
+
+              for (unsigned int line = 0;
+                   line < GeometryInfo<dim>::lines_per_cell; ++line)
+                {
+                                  // Set up the right hand side.
+                  system_rhs = 0;
+                  
+                  for (unsigned int q_point = 0; q_point <= deg; ++q_point)
+                    {
+                      const double tmp
+                        = values[line_coordinate[line]][line * this->degree
+                                                        + q_point]
+                          - local_dofs[line * this->degree]
+                          * this->shape_value_component
+                            (line * this->degree,
+                             this->generalized_support_points[line
+                                                              * this->degree
+                                                              + q_point],
+                             line_coordinate[line]);
+
+                      for (unsigned int i = 0; i < system_rhs.size (); ++i)
+                           system_rhs (i) += boundary_weights (q_point, i)
+                                             * tmp;
+                    }
+
+                  system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                  for (unsigned int i = 0; i < solution.size (); ++i)
+                    if (std::abs (solution (i)) > 1e-14)
+                      local_dofs[line * this->degree + i + 1] = solution (i);
+                }
+
+                                  // Then we go on to the
+                                  // face shape functions.
+                                  // Again we set up the
+                                  // system matrix and
+                                  // use it for both, the
+                                  // horizontal and the
+                                  // vertical, shape
+                                  // functions.
+              const std::vector<Polynomials::Polynomial<double> >&
+                legendre_polynomials
+                  = Polynomials::Legendre::generate_complete_basis (deg);
+              const unsigned int n_face_points = n_edge_points * n_edge_points;
               
-              return ((face_index != opposite_faces[shape_index][0])
-                      &&
-                      (face_index != opposite_faces[shape_index][1]));
-            };
-            
-            default: Assert (false, ExcNotImplemented());
-          };
-      };
+              system_matrix.reinit (deg * this->degree, deg * this->degree);
+              system_matrix = 0;
+
+              for (unsigned int i = 0; i <= deg; ++i)
+                for (unsigned int j = 0; j < deg; ++j)
+                  for (unsigned int k = 0; k <= deg; ++k)
+                    for (unsigned int l = 0; l < deg; ++l)
+                      for (unsigned int q_point = 0; q_point < n_face_points;
+                           ++q_point)
+                        system_matrix (i * deg + j, k * deg + l)
+                          += boundary_weights (q_point + n_edge_points,
+                                               2 * (k * deg + l))
+                             * legendre_polynomials[i].value
+                               (this->generalized_face_support_points[q_point
+                                                                      + 4
+                                                                      * n_edge_points]
+                                (0))
+                             * lobatto_polynomials[j + 2].value
+                               (this->generalized_face_support_points[q_point
+                                                                      + 4
+                                                                      * n_edge_points]
+                                (1));
+
+              system_matrix_inv.reinit (system_matrix.m (),
+                                        system_matrix.m ());
+              system_matrix_inv.invert (system_matrix);
+              solution.reinit (system_matrix.m ());
+              system_rhs.reinit (system_matrix.m ());
+              
+              const unsigned int
+                face_coordinates[GeometryInfo<3>::faces_per_cell][2]
+                  = {{1, 2}, {1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}};
+              const unsigned int
+                edge_indices[GeometryInfo<3>::faces_per_cell][GeometryInfo<3>::lines_per_face]
+                  = {{0, 4, 8, 10}, {1, 5, 9, 11}, {2, 6, 8, 9},
+                     {3, 7, 10, 11}, {2, 3, 0, 1}, {6, 7, 4, 5}};
+
+              for (unsigned int face = 0;
+                   face < GeometryInfo<dim>::faces_per_cell; ++face)
+                {
+                                  // Set up the right hand side
+                                  // for the horizontal shape
+                                  // functions.
+                  system_rhs = 0;
+
+                  for (unsigned int q_point = 0; q_point < n_face_points;
+                       ++q_point)
+                    {
+                      double tmp
+                        = values[face_coordinates[face][0]][q_point
+                                                            + GeometryInfo<dim>::lines_per_cell
+                                                            * n_edge_points];
+
+                      for (unsigned int i = 0; i < 2; ++i)
+                        for (unsigned int j = 0; j <= deg; ++j)
+                          tmp -= local_dofs[edge_indices[face][i]
+                                            * this->degree + j]
+                                 * this->shape_value_component
+                                   (edge_indices[face][i] * this->degree + j,
+                                    this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points],
+                                    face_coordinates[face][0]);
+
+                      for (unsigned int i = 0; i <= deg; ++i)
+                        for (unsigned int j = 0; j < deg; ++j)
+                          system_rhs (i * deg + j)
+                            += boundary_weights (q_point + n_edge_points,
+                                                 2 * (i * deg + j)) * tmp;
+                    }
+
+                  system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                  for (unsigned int i = 0; i <= deg; ++i)
+                    for (unsigned int j = 0; j < deg; ++j)
+                      if (std::abs (solution (i * deg + j)) > 1e-14)
+                        local_dofs[(2 * face * this->degree + i
+                                    + GeometryInfo<dim>::lines_per_cell) * deg
+                                   + j + GeometryInfo<dim>::lines_per_cell]
+                          = solution (i * deg + j);
+
+                                  // Set up the right hand side
+                                  // for the vertical shape
+                                  // functions.
+                  system_rhs = 0;
+
+                  for (unsigned int q_point = 0; q_point < n_face_points;
+                       ++q_point)
+                    {
+                      double tmp
+                        = values[face_coordinates[face][1]][q_point
+                                                            + GeometryInfo<dim>::lines_per_cell
+                                                            * n_edge_points];
+
+                      for (unsigned int i = 2;
+                           i < GeometryInfo<dim>::lines_per_face; ++i)
+                        for (unsigned int j = 0; j <= deg; ++j)
+                          tmp -= local_dofs[edge_indices[face][i]
+                                            * this->degree + j]
+                                 * this->shape_value_component
+                                   (edge_indices[face][i] * this->degree + j,
+                                    this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points],
+                                    face_coordinates[face][1]);
+
+                      for (unsigned i = 0; i <= deg; ++i)
+                        for (unsigned int j = 0; j < deg; ++j)
+                          system_rhs (i * deg + j)
+                            += boundary_weights (q_point + n_edge_points,
+                                                 2 * (i * deg + j) + 1)
+                               * tmp;
+                    }
+
+                  system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+                  for (unsigned int i = 0; i <= deg; ++i)
+                    for (unsigned int j = 0; j < deg; ++j)
+                      if (std::abs (solution (i * deg + j)) > 1e-14)
+                        local_dofs[((2 * face + 1) * deg + j + GeometryInfo<dim>::lines_per_cell)
+                                   * this->degree + i]
+                          = solution (i * deg + j);
+                }
+
+                                  // Finally we project
+                                  // the remaining parts
+                                  // of the function on
+                                  // the interior shape
+                                  // functions.
+              const QGauss<dim> reference_quadrature (this->degree);
+              const unsigned int
+                n_interior_points = reference_quadrature.size ();
+
+                                  // We create the
+                                  // system matrix.
+              system_matrix.reinit (this->degree * deg * deg,
+                                    this->degree * deg * deg);
+              system_matrix = 0;
+
+              for (unsigned int i = 0; i <= deg; ++i)
+                for (unsigned int j = 0; j < deg; ++j)
+                  for (unsigned int k = 0; k < deg; ++k)
+                    for (unsigned int l = 0; l <= deg; ++l)
+                      for (unsigned int m = 0; m < deg; ++m)
+                        for (unsigned int n = 0; n < deg; ++n)
+                          for (unsigned int q_point = 0;
+                               q_point < n_interior_points; ++q_point)
+                            system_matrix ((i * deg + j) * deg + k,
+                                           (l * deg + m) * deg + n)
+                              += reference_quadrature.weight (q_point)
+                                 * legendre_polynomials[i].value
+                                   (this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points]
+                                    (0))
+                                 * lobatto_polynomials[j + 2].value
+                                   (this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points]
+                                    (1))
+                                 * lobatto_polynomials[k + 2].value
+                                   (this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points]
+                                    (2))
+                                 * lobatto_polynomials_grad[l].value
+                                   (this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points]
+                                    (0))
+                                 * lobatto_polynomials[m + 2].value
+                                   (this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points]
+                                    (1))
+                                 * lobatto_polynomials[n + 2].value
+                                   (this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points]
+                                    (2));
+
+              system_matrix_inv.reinit (system_matrix.m (),
+                                        system_matrix.m ());
+              system_matrix_inv.invert (system_matrix);
+                                  // Set up the right hand side.
+              system_rhs.reinit (system_matrix.m ());
+              system_rhs = 0;
+
+              for (unsigned int q_point = 0; q_point < n_interior_points;
+                   ++q_point)
+                {
+                  double tmp
+                    = values[0][q_point + GeometryInfo<dim>::lines_per_cell
+                                * n_edge_points
+                                + GeometryInfo<dim>::faces_per_cell
+                                * n_face_points];
+
+                  for (unsigned int i = 0; i <= deg; ++i)
+                    {
+                      for (unsigned int j = 0; j < 2; ++j)
+                        for (unsigned int k = 0; k < 2; ++k)
+                          tmp -= local_dofs[i + (j + 4 * k + 2) * this->degree]
+                                 * this->shape_value_component
+                                   (i + (j + 4 * k + 2) * this->degree,
+                                    this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points],
+                                    0);
+
+                      for (unsigned int j = 0; j < deg; ++j)
+                        for (unsigned int k = 0; k < 4; ++k)
+                          tmp -= local_dofs[(i + 2 * (k + 2) * this->degree
+                                             + GeometryInfo<dim>::lines_per_cell)
+                                            * deg + j
+                                            + GeometryInfo<dim>::lines_per_cell]
+                                 * this->shape_value_component
+                                   ((i + 2 * (k + 2) * this->degree
+                                     + GeometryInfo<dim>::lines_per_cell)
+                                    * deg + j
+                                    + GeometryInfo<dim>::lines_per_cell,
+                                   this->generalized_support_points[q_point
+                                                                    + GeometryInfo<dim>::lines_per_cell
+                                                                    * n_edge_points
+                                                                    + GeometryInfo<dim>::faces_per_cell
+                                                                    * n_face_points],
+                                   0);
+                    }
+
+                  for (unsigned int i = 0; i <= deg; ++i)
+                    for (unsigned int j = 0; j < deg; ++j)
+                      for (unsigned int k = 0; k < deg; ++k)
+                        system_rhs ((i * deg + j) * deg + k)
+                          += reference_quadrature.weight (q_point) * tmp
+                             * lobatto_polynomials_grad[i].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points
+                                                                 + GeometryInfo<dim>::faces_per_cell
+                                                                 * n_face_points]
+                                (0))
+                             * lobatto_polynomials[j + 2].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points
+                                                                 + GeometryInfo<dim>::faces_per_cell
+                                                                 * n_face_points]
+                                (1))
+                             * lobatto_polynomials[k + 2].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points
+                                                                 + GeometryInfo<dim>::faces_per_cell
+                                                                 * n_face_points]
+                                (2));
+                }
+
+              solution.reinit (system_rhs.size ());
+              system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+              for (unsigned int i = 0; i <= deg; ++i)
+                for (unsigned int j = 0; j < deg; ++j)
+                  for (unsigned int k = 0; k < deg; ++k)
+                    if (std::abs (solution ((i * deg + j) * deg + k)) > 1e-14)
+                      local_dofs[((i + 2 * GeometryInfo<dim>::faces_per_cell)
+                                  * deg + j + GeometryInfo<dim>::lines_per_cell
+                                  + 2 * GeometryInfo<dim>::faces_per_cell)
+                                 * deg + k + GeometryInfo<dim>::lines_per_cell]
+                        = solution ((i * deg + j) * deg + k);
+
+                                  // Set up the right hand side.
+              system_rhs = 0;
+
+              for (unsigned int q_point = 0; q_point < n_interior_points;
+                   ++q_point)
+                {
+                  double tmp
+                    = values[1][q_point + GeometryInfo<dim>::lines_per_cell
+                                * n_edge_points
+                                + GeometryInfo<dim>::faces_per_cell
+                                * n_face_points];
+
+                  for (unsigned int i = 0; i <= deg; ++i)
+                    for (unsigned int j = 0; j < 2; ++j)
+                      {
+                        for (unsigned int k = 0; k < 2; ++k)
+                          tmp -= local_dofs[i + (4 * j + k) * this->degree]
+                                 * this->shape_value_component
+                                   (i + (4 * j + k) * this->degree,
+                                    this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points],
+                                    1);
+
+                        for (unsigned int k = 0; k < deg; ++k)
+                          tmp -= local_dofs[(i + 2 * j * this->degree
+                                             + GeometryInfo<dim>::lines_per_cell)
+                                            * deg + k
+                                            + GeometryInfo<dim>::lines_per_cell]
+                                 * this->shape_value_component
+                                   ((i + 2 * j * this->degree
+                                     + GeometryInfo<dim>::lines_per_cell)
+                                    * deg + k
+                                    + GeometryInfo<dim>::lines_per_cell,
+                                    this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points],
+                                    1)
+                                 + local_dofs[i + ((2 * j + 9) * deg + k
+                                                   + GeometryInfo<dim>::lines_per_cell)
+                                              * this->degree]
+                                 * this->shape_value_component
+                                   (i + ((2 * j + 9) * deg + k
+                                          + GeometryInfo<dim>::lines_per_cell)
+                                    * this->degree,
+                                    this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points],
+                                    1);
+                      }
+
+                  for (unsigned int i = 0; i <= deg; ++i)
+                    for (unsigned int j = 0; j < deg; ++j)
+                      for (unsigned int k = 0; k < deg; ++k)
+                        system_rhs ((i * deg + j) * deg + k)
+                          += reference_quadrature.weight (q_point) * tmp
+                             * lobatto_polynomials_grad[i].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points
+                                                                 + GeometryInfo<dim>::faces_per_cell
+                                                                 * n_face_points]
+                                (1))
+                             * lobatto_polynomials[j + 2].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points
+                                                                 + GeometryInfo<dim>::faces_per_cell
+                                                                 * n_face_points]
+                                (0))
+                             * lobatto_polynomials[k + 2].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points
+                                                                 + GeometryInfo<dim>::faces_per_cell
+                                                                 * n_face_points]
+                                (2));
+                }
+
+              system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+              for (unsigned int i = 0; i <= deg; ++i)
+                for (unsigned int j = 0; j < deg; ++j)
+                  for (unsigned int k = 0; k < deg; ++k)
+                    if (std::abs (solution ((i * deg + j) * deg + k)) > 1e-14)
+                      local_dofs[((i + this->degree + 2
+                                   * GeometryInfo<dim>::faces_per_cell) * deg
+                                  + j + GeometryInfo<dim>::lines_per_cell + 2
+                                  * GeometryInfo<dim>::faces_per_cell) * deg
+                                  + k + GeometryInfo<dim>::lines_per_cell]
+                        = solution ((i * deg + j) * deg + k);
+
+                                  // Set up the right hand side.
+              system_rhs = 0;
+
+              for (unsigned int q_point = 0; q_point < n_interior_points;
+                   ++q_point)
+                {
+                  double tmp
+                    = values[2][q_point + GeometryInfo<dim>::lines_per_cell
+                                * n_edge_points
+                                + GeometryInfo<dim>::faces_per_cell
+                                * n_face_points];
+
+                  for (unsigned int i = 0; i <= deg; ++i)
+                    for (unsigned int j = 0; j < 4; ++j)
+                      {
+                        tmp -= local_dofs[i + (j + 8) * this->degree]
+                               * this->shape_value_component
+                                 (i + (j + 8) * this->degree,
+                                  this->generalized_support_points[q_point
+                                                                   + GeometryInfo<dim>::lines_per_cell
+                                                                   * n_edge_points
+                                                                   + GeometryInfo<dim>::faces_per_cell
+                                                                   * n_face_points],
+                                  2);
+
+                        for (unsigned int k = 0; k < deg; ++k)
+                          tmp -= local_dofs[i + ((2 * j + 1) * deg + k
+                                                 + GeometryInfo<dim>::lines_per_cell)
+                                            * this->degree]
+                                 * this->shape_value_component
+                                   (i + ((2 * j + 1) * deg + k
+                                         + GeometryInfo<dim>::lines_per_cell)
+                                    * this->degree,
+                                    this->generalized_support_points[q_point
+                                                                     + GeometryInfo<dim>::lines_per_cell
+                                                                     * n_edge_points
+                                                                     + GeometryInfo<dim>::faces_per_cell
+                                                                     * n_face_points],
+                                    2);
+                      }
+
+                  for (unsigned int i = 0; i <= deg; ++i)
+                    for (unsigned int j = 0; j < deg; ++j)
+                      for (unsigned int k = 0; k < deg; ++k)
+                        system_rhs ((i * deg + j) * deg + k)
+                          += reference_quadrature.weight (q_point) * tmp
+                             * lobatto_polynomials_grad[i].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points
+                                                                 + GeometryInfo<dim>::faces_per_cell
+                                                                 * n_face_points]
+                                (2))
+                             * lobatto_polynomials[j + 2].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points
+                                                                 + GeometryInfo<dim>::faces_per_cell
+                                                                 * n_face_points]
+                                (0))
+                             * lobatto_polynomials[k + 2].value
+                               (this->generalized_support_points[q_point
+                                                                 + GeometryInfo<dim>::lines_per_cell
+                                                                 * n_edge_points
+                                                                 + GeometryInfo<dim>::faces_per_cell
+                                                                 * n_face_points]
+                                (1));
+                }
+
+              system_matrix_inv.vmult (solution, system_rhs);
+
+                                  // Add the computed values
+                                  // to the resulting vector
+                                  // only, if they are not
+                                  // too small.
+              for (unsigned int i = 0; i <= deg; ++i)
+                for (unsigned int j = 0; j < deg; ++j)
+                  for (unsigned int k = 0; k < deg; ++k)
+                    if (std::abs (solution ((i * deg + j) * deg + k)) > 1e-14)
+                      local_dofs[i + ((j + 2 * (deg
+                                                + GeometryInfo<dim>::faces_per_cell))
+                                      * deg + k
+                                      + GeometryInfo<dim>::lines_per_cell)
+                                 * this->degree]
+                        = solution ((i * deg + j) * deg + k);
+            }
+          
+          break;
+        }
       
-      default:  // other degree
-            Assert (false, ExcNotImplemented());
-    };
-  
-  return true;
+      default:
+        Assert (false, ExcNotImplemented ());
+    }
 }
 
 
-
-template <int dim, int spacedim>
+template <int dim>
 unsigned int
-FE_Nedelec<dim,spacedim>::memory_consumption () const
+FE_Nedelec<dim>::memory_consumption () const
 {
   Assert (false, ExcNotImplemented ());
   return 0;
 }
 
 
-
-template <int dim, int spacedim>
-unsigned int
-FE_Nedelec<dim,spacedim>::get_degree () const
-{
-  return degree;
-}
-
-
 template class FE_Nedelec<deal_II_dimension>;
 
 DEAL_II_NAMESPACE_CLOSE
-
index db97ccb8b34ae52799c4bc75665bd05d94a76a81..3665e721852ce5d1d27930bfc95946d116840d80 100644 (file)
@@ -15,6 +15,7 @@
 #include <base/polynomials_bdm.h>
 #include <base/polynomials_raviart_thomas.h>
 #include <base/polynomials_abf.h>
+#include <base/polynomials_nedelec.h>
 #include <fe/fe_poly_tensor.h>
 #include <fe/fe_values.h>
 #include <fe/mapping_cartesian.h>
@@ -433,6 +434,18 @@ FE_PolyTensor<POLY,dim,spacedim>::fill_fe_values (
                    = sign_change[i] * shape_values[k][d];
              break;
            }
+         
+         case mapping_nedelec: {
+            std::vector<Tensor<1,dim> > shape_values (n_q_points);
+            mapping.transform (fe_data.shape_values[i], shape_values,
+              mapping_data, mapping_covariant);
+                
+            for (unsigned int k = 0; k < n_q_points; ++k)
+               for (unsigned int d = 0; d < dim; ++d)
+                  data.shape_values(first+d,k) = shape_values[k][d];
+             
+            break;
+         }
 
          default:
            Assert(false, ExcNotImplemented());
@@ -487,6 +500,46 @@ FE_PolyTensor<POLY,dim,spacedim>::fill_fe_values (
                
                break;
              }
+             
+             case mapping_nedelec: {
+                                           // treat the gradients of
+                                           // this particular shape
+                                           // function at all
+                                           // q-points. if Dv is the
+                                           // gradient of the shape
+                                           // function on the unit
+                                           // cell, then
+                                           // (J^-T)Dv(J^-1) is the
+                                           // value we want to have on
+                                           // the real cell. so, we
+                                           // will have to apply a
+                                           // covariant transformation
+                                           // to Dv twice. since the
+                                           // interface only allows
+                                           // multiplication with
+                                           // (J^-1) from the right,
+                                           // we have to trick a
+                                           // little in between
+                                           
+                                           // do first transformation
+                mapping.transform (fe_data.shape_grads[i], shape_grads1,
+                  mapping_data, mapping_covariant);
+                                           // transpose matrix          
+                for (unsigned int k = 0; k < n_q_points; ++k)
+                   shape_grads2[k] = transpose (shape_grads1[k]);
+                                           // do second transformation          
+                mapping.transform (shape_grads2, shape_grads1,
+                  mapping_data, mapping_covariant);
+                                           // transpose back            
+                for (unsigned int k = 0; k < n_q_points; ++k)
+                   shape_grads2[k] = transpose (shape_grads1[k]);
+                   
+                for (unsigned int k = 0; k < n_q_points; ++k)
+                   for (unsigned int d = 0; d < dim; ++d)
+                      data.shape_gradients[first + d][k] = shape_grads2[k][d];          
+                                          // then copy over to target:
+                break;
+             }
                    
              default:
                Assert(false, ExcNotImplemented());
@@ -589,9 +642,21 @@ FE_PolyTensor<POLY,dim,spacedim>::fill_fe_face_values (
                break;
              }
              
+             case mapping_nedelec: {
+                std::vector<Tensor<1,dim> > shape_values (n_q_points);
+                  mapping.transform (make_slice (fe_data.shape_values[i], offset, n_q_points),
+                shape_values, mapping_data, mapping_covariant);
+                
+                for (unsigned int k = 0; k < n_q_points; ++k)
+                   for (unsigned int d = 0; d < dim; ++d)
+                      data.shape_values(first+d,k) = shape_values[k][d];
+             
+                break;
+             }
+         
              default:
                Assert(false, ExcNotImplemented());
-           }
+           }     
        }
       
       if (flags & update_gradients)
@@ -644,6 +709,46 @@ FE_PolyTensor<POLY,dim,spacedim>::fill_fe_face_values (
                break;
              }
              
+             case mapping_nedelec: {
+                                           // treat the gradients of
+                                           // this particular shape
+                                           // function at all
+                                           // q-points. if Dv is the
+                                           // gradient of the shape
+                                           // function on the unit
+                                           // cell, then
+                                           // (J^-T)Dv(J^-1) is the
+                                           // value we want to have on
+                                           // the real cell. so, we
+                                           // will have to apply a
+                                           // covariant transformation
+                                           // to Dv twice. since the
+                                           // interface only allows
+                                           // multiplication with
+                                           // (J^-1) from the right,
+                                           // we have to trick a
+                                           // little in between
+                                           
+                                           // do first transformation
+                mapping.transform (make_slice (fe_data.shape_grads[i], offset, n_q_points),
+                  shape_grads1, mapping_data, mapping_covariant);
+                                           // transpose matrix          
+                for (unsigned int k = 0; k < n_q_points; ++k)
+                   shape_grads2[k] = transpose (shape_grads1[k]);
+                                           // do second transformation          
+                mapping.transform (shape_grads2, shape_grads1,
+                  mapping_data, mapping_covariant);
+                                           // transpose back            
+                for (unsigned int k = 0; k < n_q_points; ++k)
+                   shape_grads2[k] = transpose (shape_grads1[k]);
+                   
+                for (unsigned int k = 0; k < n_q_points; ++k)
+                   for (unsigned int d = 0; d < dim; ++d)
+                      data.shape_gradients[first + d][k] = shape_grads2[k][d];          
+                                          // then copy over to target:
+                break;
+             }
+             
              default:
                Assert(false, ExcNotImplemented());
            }
@@ -882,6 +987,19 @@ FE_PolyTensor<POLY,dim,spacedim>::update_each (const UpdateFlags flags) const
        break;
       }
       
+      case mapping_nedelec: {
+        if (flags & update_values)
+           out |= update_values | update_covariant_transformation;
+        
+        if (flags & update_gradients)
+           out |= update_gradients | update_covariant_transformation;
+        
+        if (flags & update_hessians)
+           out |= update_hessians | update_covariant_transformation;
+       
+         break;
+      }
+
       default:
       {
        Assert (false, ExcNotImplemented());
@@ -896,7 +1014,7 @@ FE_PolyTensor<POLY,dim,spacedim>::update_each (const UpdateFlags flags) const
 template class FE_PolyTensor<PolynomialsRaviartThomas<deal_II_dimension>,deal_II_dimension>;
 template class FE_PolyTensor<PolynomialsABF<deal_II_dimension>,deal_II_dimension>;
 template class FE_PolyTensor<PolynomialsBDM<deal_II_dimension>,deal_II_dimension>;
-
+template class FE_PolyTensor<PolynomialsNedelec<deal_II_dimension>, deal_II_dimension>;
 
 
 DEAL_II_NAMESPACE_CLOSE

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.