From: Markus Buerg Date: Sun, 12 Sep 2010 09:03:07 +0000 (+0000) Subject: Nedelec elements in prerelease version. Requires documentation and style changes... X-Git-Tag: v8.0.0~5541 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d558bccde4a8c875471fa89da046ddad1b9564c7;p=dealii.git Nedelec elements in prerelease version. Requires documentation and style changes and tests. git-svn-id: https://svn.dealii.org/trunk@21932 0785d39b-7218-0410-832d-ea1e28bc413d --- diff --git a/deal.II/base/include/base/polynomial.h b/deal.II/base/include/base/polynomial.h index 81f8b79c47..c9c4514c45 100644 --- a/deal.II/base/include/base/polynomial.h +++ b/deal.II/base/include/base/polynomial.h @@ -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 #include #include -#include #include @@ -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 class Polynomial : public Subscriptor @@ -69,18 +68,12 @@ namespace Polynomials */ Polynomial (const std::vector &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& operator += (const Polynomial& p); - + /** * Subtract a second polynomial. */ Polynomial& operator -= (const Polynomial& p); - + /** * Print coefficients. */ @@ -227,7 +220,7 @@ namespace Polynomials */ static void multiply (std::vector& 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 > generate_complete_basis (const unsigned int degree); - + private: /** * Needed by constructor. @@ -287,7 +280,7 @@ namespace Polynomials static std::vector make_vector(unsigned int n, const double coefficient); }; - + /** * Lagrange polynomials with equidistant interpolation points in @@ -341,7 +334,7 @@ namespace Polynomials static std::vector > generate_complete_basis (const unsigned int degree); - + private: /** @@ -352,11 +345,10 @@ namespace Polynomials * called in the * constructor. */ - static - void + static + std::vector compute_coefficients (const unsigned int n, - const unsigned int support_point, - std::vector& a); + const unsigned int support_point); }; /** @@ -381,9 +373,9 @@ namespace Polynomials std::vector > generate_complete_basis (const std::vector >& points); }; - - - + + + /** * Legendre polynomials of arbitrary degree on [0,1]. * @@ -420,33 +412,30 @@ namespace Polynomials static std::vector > generate_complete_basis (const unsigned int degree); - + private: /** * Coefficients for the interval $[0,1]$. */ - static std::vector > > shifted_coefficients; - + static std::vector *> 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 > > recursive_coefficients; - + static std::vector *> 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 [0,1]. + * + * 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 k will generate the polynomial with index k. But only for $k\geq1$ the index equals the degree of the polynomial. For k==0 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 { + public: + /** + * Constructor for polynomial of degree p. There is an exception for p==0, see the general documentation. + */ + Lobatto (const unsigned int p = 0); + + /** + * Return the polynomials with index 0 up to degree. There is an exception for p==0, see the general + * documentation. + */ + static std::vector > generate_complete_basis (const unsigned int p); + + private: + /** + * Compute coefficients recursively. + */ + std::vector compute_coefficients (const unsigned int p); +}; /** * Hierarchical polynomials of arbitrary degree on [0,1]. * - * When Constructing a Hierarchical polynomial of degree p, + * When Constructing a Hierarchical polynomial of degree p, * 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 p will generate the @@ -533,7 +551,7 @@ namespace Polynomials static std::vector > generate_complete_basis (const unsigned int degree); - + private: /** * Compute coefficients recursively. @@ -549,22 +567,22 @@ namespace Polynomials */ static const std::vector & get_coefficients (const unsigned int p); - + static std::vector *> recursive_coefficients; - }; + }; } /** @} */ /* -------------------------- inline functions --------------------- */ -namespace Polynomials +namespace Polynomials { template inline - Polynomial::Polynomial () + Polynomial::Polynomial () {} - + template 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 index 0000000000..90f419f4a5 --- /dev/null +++ b/deal.II/base/include/base/polynomials_nedelec.h @@ -0,0 +1,150 @@ +#ifndef __deal2__polynomials_nedelec_h +#define __deal2__polynomials_nedelec_h + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +DEAL_II_NAMESPACE_OPEN +/** + * @addtogroup Polynomials + * @{ + */ + +/** + * This class implements the Hcurl-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 Qk. + * Therefore, the polynomial order of each component must be one + * order higher in the corresponding two directions, + * yielding the polynomial spaces (Qk,k+1, + * Qk+1,k) and (Qk,k+1,k+1, + * Qk+1,k,k+1, Qk+1,k+1,k) in 2D and 3D, resp. + * + * @author Markus Bürg, 2009 + */ +template +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 + * Qk 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 + * n(). 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 + * compute_value, + * compute_grad or + * compute_grad_grad + * functions, see below, in a + * loop over all tensor product + * polynomials. + */ + void compute (const Point &unit_point, std::vector > &values, std::vector > &grads, std::vector > &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 + * N(degree) 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 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 > > create_polynomials (const unsigned int k); +}; + +/** @} */ + +template +inline unsigned int PolynomialsNedelec::n () const +{ + return n_pols; +} + +template +inline unsigned int PolynomialsNedelec::degree () const +{ + return my_degree; +} +DEAL_II_NAMESPACE_CLOSE + +#endif diff --git a/deal.II/base/source/polynomial.cc b/deal.II/base/source/polynomial.cc index b8663860e6..e82e048956 100644 --- a/deal.II/base/source/polynomial.cc +++ b/deal.II/base/source/polynomial.cc @@ -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 - Polynomial::Polynomial (const unsigned int n) - : - coefficients(n+1, 0.) - {} - - - template void Polynomial::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 Polynomial& Polynomial::operator *= (const Polynomial& p) @@ -169,16 +161,16 @@ namespace Polynomials unsigned int new_degree = this->degree() + p.degree(); std::vector new_coefficients(new_degree+1, 0.); - + for (unsigned int i=0; icoefficients.size(); ++j) new_coefficients[i+j] += this->coefficients[j]*p.coefficients[i]; this->coefficients = new_coefficients; - + return *this; } - + template Polynomial& Polynomial::operator += (const Polynomial& p) @@ -194,7 +186,7 @@ namespace Polynomials return *this; } - + template Polynomial& Polynomial::operator -= (const Polynomial& p) @@ -210,13 +202,13 @@ namespace Polynomials return *this; } - + template template void Polynomial::shift(std::vector& 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 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 Polynomial Polynomial::derivative () const @@ -305,7 +297,7 @@ namespace Polynomials return Polynomial (newcoefficients); } - + template Polynomial @@ -318,7 +310,7 @@ namespace Polynomials return Polynomial (newcoefficients); } - + template void @@ -343,15 +335,15 @@ namespace Polynomials result[n] = coefficient; return result; } - - + + template Monomial::Monomial (unsigned int n, double coefficient) : Polynomial(make_vector(n, coefficient)) {} - - + + template std::vector > Monomial::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(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 two (2, 1.); - for (unsigned int k=0;k<=n;++k) - { - if (k != support_point) - { - two[0] = -1.*k/n; - Polynomial factor(two); - factor.scale(1.*n/(support_point - k)); - (*this) *= factor; - } - } - } - } - - - void + std::vector LagrangeEquidistant::compute_coefficients (const unsigned int n, - const unsigned int support_point, - std::vector& a) + const unsigned int support_point) { + std::vector a (n+1); Assert(support_point > Lagrange::generate_complete_basis (const std::vector >& points) { @@ -657,7 +621,7 @@ namespace Polynomials std::vector linear(2, 1.); // We start with a constant polynomial std::vector one(1, 1.); - + for (unsigned int i=0;i::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 > > - Legendre::recursive_coefficients(20); - std::vector > > - Legendre::shifted_coefficients(20); + std::vector *> + Legendre::recursive_coefficients(20, + static_cast*>(0)); + std::vector *> + Legendre::shifted_coefficients(20, + static_cast*>(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 >()))) + (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 >(c0); - recursive_coefficients[1] = - std_cxx1x::shared_ptr >(c1); - + // const + recursive_coefficients[0] = c0; + recursive_coefficients[1] = c1; // Compute polynomials // orthogonal on [0,1] c0 = new std::vector(*c0); c1 = new std::vector(*c1); - + Polynomial::shift (*c0, -1.); Polynomial::scale(*c0, 2.); Polynomial::shift (*c1, -1.); Polynomial::scale(*c1, 2.); Polynomial::multiply(*c1, std::sqrt(3.)); - shifted_coefficients[0]=std_cxx1x::shared_ptr >(c0); - shifted_coefficients[1]=std_cxx1x::shared_ptr >(c1); + shifted_coefficients[0]=c0; + shifted_coefficients[1]=c1; } else { @@ -810,11 +776,11 @@ namespace Polynomials coefficients_lock.acquire (); std::vector *ck = new std::vector(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 >(ck); + recursive_coefficients[k] = ck; // and compute the // coefficients for [0,1] ck = new std::vector(*ck); Polynomial::shift (*ck, -1.); Polynomial::scale(*ck, 2.); Polynomial::multiply(*ck, std::sqrt(2.*k+1.)); - shifted_coefficients[k] = - std_cxx1x::shared_ptr >(ck); + shifted_coefficients[k] = ck; }; }; } @@ -870,6 +834,81 @@ namespace Polynomials } +// ------------------ class Lobatto -------------------- // + + +Lobatto::Lobatto (const unsigned int p) : Polynomial (compute_coefficients (p)) { +} + +std::vector Lobatto::compute_coefficients (const unsigned int p) { + switch (p) { + case 0: { + std::vector coefficients (2); + + coefficients[0] = 1.0; + coefficients[1] = -1.0; + return coefficients; + } + + case 1: { + std::vector coefficients (2); + + coefficients[0] = 0.0; + coefficients[1] = 1.0; + return coefficients; + } + + case 2: { + std::vector coefficients (3); + + coefficients[0] = 0.0; + coefficients[1] = -1.0 * std::sqrt (3); + coefficients[2] = std::sqrt (3); + return coefficients; + } + + default: { + std::vector coefficients (p + 1); + std::vector legendre_coefficients_tmp1 (p); + std::vector 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 > Lobatto::generate_complete_basis (const unsigned int p) { + std::vector > 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 *ck = new std::vector(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 index 0000000000..24c76b9703 --- /dev/null +++ b/deal.II/base/source/polynomials_nedelec.cc @@ -0,0 +1,496 @@ +#include +#include +#include +#include +#include +#include + +DEAL_II_NAMESPACE_OPEN + + +template +PolynomialsNedelec::PolynomialsNedelec (const unsigned int k) : my_degree (k), polynomial_space (create_polynomials (k)), n_pols (compute_n_pols (k)) { +} + +template +std::vector > > PolynomialsNedelec::create_polynomials (const unsigned int k) { + std::vector > > 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 +void PolynomialsNedelec::compute (const Point &unit_point, std::vector > &values, std::vector > &grads, std::vector > &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 polynomial_space at unit_point + const unsigned int n_basis = polynomial_space.n (); + std::vector unit_point_values ((values.size () == 0) ? 0 : n_basis); + std::vector > unit_point_grads ((grads.size () == 0) ? 0 : n_basis); + std::vector > 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 polynomial_space at unit_point with coordinates + // shifted one step in positive direction + Point p; + std::vector p_values ((values.size () == 0) ? 0 : n_basis); + std::vector > p_grads ((grads.size () == 0) ? 0 : n_basis); + std::vector > 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::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][0] = unit_point_values[i + (j + 2) * (my_degree + 1)]; + values[(i + GeometryInfo::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][1] = 0.0; + values[i + (j + my_degree + GeometryInfo::lines_per_cell) * (my_degree + 1)][0] = 0.0; + values[i + (j + my_degree + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][0][k] = unit_point_grads[i + (j + 2) * (my_degree + 1)][k]; + grads[(i + GeometryInfo::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][1][k] = 0.0; + grads[i + (j + my_degree + GeometryInfo::lines_per_cell) * (my_degree + 1)][0][k] = 0.0; + } + + grads[i + (j + my_degree + GeometryInfo::lines_per_cell) * (my_degree + 1)][1][0] = p_grads[i + (j + 2) * (my_degree + 1)][1]; + grads[i + (j + my_degree + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][0][k][l] = unit_point_grad_grads[i + (j + 2) * (my_degree + 1)][k][l]; + grad_grads[(i + GeometryInfo::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][1][k][l] = 0.0; + grad_grads[i + (j + my_degree + GeometryInfo::lines_per_cell) * (my_degree + 1)][0][k][l] = 0.0; + } + + grad_grads[i + (j + my_degree + GeometryInfo::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::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::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::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 polynomial_space at unit_point with coordinates + // shifted two steps in positive direction + Point p1, p2; + std::vector p1_values ((values.size () == 0) ? 0 : n_basis); + std::vector > p1_grads ((grads.size () == 0) ? 0 : n_basis); + std::vector > p1_grad_grads ((grad_grads.size () == 0) ? 0 : n_basis); + std::vector p2_values ((values.size () == 0) ? 0 : n_basis); + std::vector > p2_grads ((grads.size () == 0) ? 0 : n_basis); + std::vector > 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::faces_per_cell) * my_degree + j + GeometryInfo::lines_per_cell + 2 * GeometryInfo::faces_per_cell) * my_degree + k + GeometryInfo::lines_per_cell][l + 1] = 0; + values[(i + (j + 2 * GeometryInfo::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::lines_per_cell][2 * l] = 0; + values[i + (j + (k + 2 * (GeometryInfo::faces_per_cell + my_degree)) * my_degree + GeometryInfo::lines_per_cell) * (my_degree + 1)][l] = 0; + } + + values[((i + 2 * GeometryInfo::faces_per_cell) * my_degree + j + GeometryInfo::lines_per_cell + 2 * GeometryInfo::faces_per_cell) * my_degree + k + GeometryInfo::lines_per_cell][0] = unit_point_values[i + (j + (k + 2) * (my_degree + 2) + 2) * (my_degree + 1)]; + values[(i + (j + 2 * GeometryInfo::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::lines_per_cell][1] = p1_values[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)]; + values[i + (j + (k + 2 * (GeometryInfo::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::lines_per_cell) * (my_degree + 1)][m] = 0; + values[(i + 2 * (k + 2 * (l + 1)) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][m + 1] = 0; + } + + values[(i + 2 * k * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][2 * l] = 0; + values[i + (j + (2 * k + 9) * my_degree + GeometryInfo::lines_per_cell) * (my_degree + 1)][2 * l] = 0; + } + + values[(i + 2 * k * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + j + GeometryInfo::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::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::lines_per_cell) * my_degree + j + GeometryInfo::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::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::lines_per_cell) * my_degree + j + GeometryInfo::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::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::faces_per_cell) * my_degree + j + GeometryInfo::lines_per_cell + 2 * GeometryInfo::faces_per_cell) * my_degree + k + GeometryInfo::lines_per_cell][m + 1][l] = 0; + grads[(i + (j + 2 * GeometryInfo::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::lines_per_cell][2 * m][l] = 0; + grads[i + (j + (k + 2 * (GeometryInfo::faces_per_cell + my_degree)) * my_degree + GeometryInfo::lines_per_cell) * (my_degree + 1)][m][l] = 0; + } + + grads[((i + 2 * GeometryInfo::faces_per_cell) * my_degree + j + GeometryInfo::lines_per_cell + 2 * GeometryInfo::faces_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::lines_per_cell][1][0] = p1_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][2]; + grads[(i + (j + 2 * GeometryInfo::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::lines_per_cell][1][1] = p1_grads[i + ((j + 2) * (my_degree + 2) + k + 2) * (my_degree + 1)][0]; + grads[(i + (j + 2 * GeometryInfo::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::lines_per_cell) * (my_degree + 1)][n][m] = 0; + grads[(i + 2 * (k + 2 * (l + 1)) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][n + 1][m] = 0; + } + + grads[(i + 2 * k * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][2 * l][m] = 0; + grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::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::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::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::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::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::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::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::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::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::faces_per_cell) * my_degree + j + GeometryInfo::lines_per_cell + 2 * GeometryInfo::faces_per_cell) * my_degree + k + GeometryInfo::lines_per_cell][n + 1][l][m] = 0; + grad_grads[(i + (j + 2 * GeometryInfo::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::lines_per_cell][2 * n][l][m] = 0; + grad_grads[i + (j + (k + 2 * (GeometryInfo::faces_per_cell + my_degree)) * my_degree + GeometryInfo::lines_per_cell) * (my_degree + 1)][n][l][m] = 0; + } + + grad_grads[((i + 2 * GeometryInfo::faces_per_cell) * my_degree + j + GeometryInfo::lines_per_cell + 2 * GeometryInfo::faces_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + k + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::faces_per_cell + my_degree)) * my_degree + GeometryInfo::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::lines_per_cell) * (my_degree + 1)][o][l][m] = 0; + grad_grads[(i + 2 * (k + 2 * (n + 1)) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][o + 1][l][m] = 0; + } + + grad_grads[(i + 2 * k * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + j + GeometryInfo::lines_per_cell][2 * n][l][m] = 0; + grad_grads[i + (j + (2 * k + 9) * my_degree + GeometryInfo::lines_per_cell) * (my_degree + 1)][2 * n][l][m] = 0; + } + + grad_grads[(i + 2 * (k + 2) * (my_degree + 1) + GeometryInfo::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::lines_per_cell) * my_degree + j + GeometryInfo::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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 +unsigned int PolynomialsNedelec::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 diff --git a/deal.II/deal.II/include/fe/fe_nedelec.h b/deal.II/deal.II/include/fe/fe_nedelec.h index 4752213786..80b24e752f 100644 --- a/deal.II/deal.II/include/fe/fe_nedelec.h +++ b/deal.II/deal.II/include/fe/fe_nedelec.h @@ -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 +#include +#include +#include +#include +#include +#include #include #include +#include +#include DEAL_II_NAMESPACE_OPEN @@ -26,173 +22,59 @@ template 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 Hcurl. 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. p==1) 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 degree. * - * This class has not yet been implemented for the codimension one case + * This class is not implemented for the codimension one case * (spacedim != dim). * + * @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. * - *

Restriction on transformations

+ *

Interpolation

* - * 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. + *

Node values

* - * 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: + *

Generalized support points

* - * 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 + * QGaussk+1 on each edge and QGaussk+2 on each face and in + * the interior of the cell (or none for N1). * - * 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. - * - * - *

Interpolation to finer and coarser meshes

* - * 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. - * - * - *

Numbering of the degrees of freedom (DoFs)

- * - * 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 -class FE_Nedelec : public FiniteElement -{ - public: +template +class FE_Nedelec : public FE_PolyTensor, 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 */ 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 &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 &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 FE_Nedelec 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 &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, base_element(0) is - * @p this, and all other - * indices throw an error. - */ - virtual const FiniteElement & - base_element (const unsigned int index) const; + virtual std::vector > hp_vertex_dof_identities (const FiniteElement& fe_other) const; - /** - * Multiplicity of base element - * @p index. Since this is an - * atomic element, - * element_multiplicity(0) - * 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 > hp_line_dof_identities (const FiniteElement& 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 > hp_quad_dof_identities (const FiniteElement& 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 fe_nedelec_[23]d.cc - * 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 source.dofs_per_face + * times this->dofs_per_face. + * + * 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 + * FiniteElement::ExcInterpolationNotImplemented. */ - 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::max_children_per_cell]; + virtual void get_face_interpolation_matrix (const FiniteElement& source, FullMatrix& 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 source.dofs_per_face times + * this->dofs_per_face. * - * This function is needed by the - * constructors of @p FESystem. - */ - virtual FiniteElement * 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 + * ExcInterpolationNotImplemented. */ - virtual - typename Mapping::InternalDataBase * - get_data (const UpdateFlags, - const Mapping& mapping, - const Quadrature& quadrature) const ; + virtual void get_subface_interpolation_matrix (const FiniteElement& source, const unsigned int subface, FullMatrix& matrix) const; - /** - * Implementation of the same - * function in - * FiniteElement. - */ - virtual void - fill_fe_values (const Mapping &mapping, - const typename Triangulation::cell_iterator &cell, - const Quadrature &quadrature, - typename Mapping::InternalDataBase &mapping_internal, - typename Mapping::InternalDataBase &fe_internal, - FEValuesData &data, - CellSimilarity::Similarity &cell_similarity) const; - - /** - * Implementation of the same - * function in - * FiniteElement. - */ - virtual void - fill_fe_face_values (const Mapping &mapping, - const typename Triangulation::cell_iterator &cell, - const unsigned int face_no, - const Quadrature &quadrature, - typename Mapping::InternalDataBase &mapping_internal, - typename Mapping::InternalDataBase &fe_internal, - FEValuesData& data) const ; - - /** - * Implementation of the same - * function in - * FiniteElement. - */ - virtual void - fill_fe_subface_values (const Mapping &mapping, - const typename Triangulation::cell_iterator &cell, - const unsigned int face_no, - const unsigned int sub_no, - const Quadrature &quadrature, - typename Mapping::InternalDataBase &mapping_internal, - typename Mapping::InternalDataBase &fe_internal, - FEValuesData& data) const ; + virtual void interpolate (std::vector& local_dofs, const std::vector& values) const; - private: + virtual void interpolate (std::vector& local_dofs, const std::vector >& values, unsigned int offset = 0) const; + virtual void interpolate (std::vector& local_dofs, const VectorSlice > >& values) const; + virtual unsigned int memory_consumption () const; + virtual FiniteElement * 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 * be passed to the constructor of * @p FiniteElementData. */ - static std::vector get_dpo_vector(const unsigned int degree); - + static std::vector 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 * see the documentation of the * base class. */ - class InternalData : public FiniteElement::InternalDataBase + class InternalData : public FiniteElement::InternalDataBase { public: /** @@ -581,7 +249,7 @@ class FE_Nedelec : public FiniteElement * multiplication with the * Jacobian of the mapping. */ - std::vector > > shape_values; + std::vector > > shape_values; /** * Array with shape function @@ -601,127 +269,39 @@ class FE_Nedelec : public FiniteElement * multiplication) when * visiting an actual cell. */ - std::vector > > shape_gradients; + std::vector > > 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 friend class FE_Nedelec; + template 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 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 diff --git a/deal.II/deal.II/source/fe/fe_nedelec.cc b/deal.II/deal.II/source/fe/fe_nedelec.cc index cd958fbb23..363b8d00e7 100644 --- a/deal.II/deal.II/source/fe/fe_nedelec.cc +++ b/deal.II/deal.II/source/fe/fe_nedelec.cc @@ -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 +#include #include +#include #include -#include #include #include #include -#include #include #include +#include #include - +#include +#include +#include #include +#include + +//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 -FE_Nedelec::FE_Nedelec (const unsigned int degree) - : - FiniteElement ( - FiniteElementData(get_dpo_vector(degree), dim, - degree+1, FiniteElementData::Hcurl, 1), - std::vector ( - FiniteElementData(get_dpo_vector(degree), dim, - degree+1).dofs_per_cell,false), - std::vector >( - FiniteElementData(get_dpo_vector(degree), dim, - degree+1).dofs_per_cell, - std::vector(dim,true))), - degree(degree) +template +FE_Nedelec::FE_Nedelec (const unsigned int p) : +FE_PolyTensor, dim> +(p, + FiniteElementData (get_dpo_vector (p), dim, p + 1, + FiniteElementData::Hcurl, 1), + std::vector (PolynomialsNedelec::compute_n_pols (p), true), + std::vector > + (PolynomialsNedelec::compute_n_pols (p), + std::vector (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 (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 face_embeddings[GeometryInfo::max_children_per_face]; + + for (unsigned int i = 0; i < GeometryInfo::max_children_per_face; ++i) + face_embeddings[i].reinit (this->dofs_per_face, this->dofs_per_face); + + FETools::compute_face_embedding_matrices + (*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::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 +template std::string -FE_Nedelec::get_name () const +FE_Nedelec::get_name () const { // note that the // FETools::get_fe_from_name @@ -92,1430 +100,5866 @@ FE_Nedelec::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 -FiniteElement * -FE_Nedelec::clone() const +template +FiniteElement +*FE_Nedelec::clone () const { - return new FE_Nedelec(*this); + return new FE_Nedelec (*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 +void +FE_Nedelec::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 +void +FE_Nedelec::initialize_support_points (const unsigned int degree) { - const unsigned int dim = 2; - - Assert (idofs_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 >& lobatto_polynomials + = Polynomials::Lobatto::generate_complete_basis (degree + 1); + std::vector > + 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 (idofs_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 reference_edge_quadrature (degree + 1); + const unsigned int& + n_edge_points = reference_edge_quadrature.size (); + const unsigned int n_boundary_points + = GeometryInfo::lines_per_cell * n_edge_points; + const Quadrature& edge_quadrature + = QProjector::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 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::lines_per_cell; ++line) + this->generalized_support_points[line * n_edge_points + + q_point] + = edge_quadrature.point + (QProjector::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& edge_quadrature + = QProjector::project_to_all_faces + (reference_edge_quadrature); + + this->generalized_support_points.resize (n_boundary_points); + + for (unsigned int line = 0; + line < GeometryInfo::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::DataSetDescriptor::face + (line, true, false, false, n_edge_points) + q_point); + } + + break; + } + + case 3: + { + // Initialize quadratures to obtain + // quadrature points later on. + const QGauss reference_edge_quadrature (degree + 1); + const unsigned int& n_edge_points = reference_edge_quadrature.size (); + const Quadrature& edge_quadrature + = QProjector::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 reference_face_quadrature (degree + 1); + const unsigned int& n_face_points + = reference_face_quadrature.size (); + const unsigned int n_boundary_points + = GeometryInfo::lines_per_cell * n_edge_points + + GeometryInfo::faces_per_cell * n_face_points; + const QGauss 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::lines_per_cell; ++line) + this->generalized_face_support_points[line * n_edge_points + + q_point] + = edge_quadrature.point + (QProjector::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 + (i, reference_edge_quadrature.point (q_point) (0), + j); + this->generalized_support_points + [q_point + (i + 4 * j + 2) * n_edge_points] + = Point + (reference_edge_quadrature.point (q_point) (0), + i, j); + this->generalized_support_points + [q_point + (i + 2 * (j + 4)) * n_edge_points] + = Point + (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& face_quadrature + = QProjector::project_to_all_faces + (reference_face_quadrature); + + for (unsigned int face = 0; + face < GeometryInfo::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::lines_per_cell * n_edge_points] + = face_quadrature.point + (QProjector::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::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::lines_per_cell; ++line) + this->generalized_face_support_points[line * n_edge_points + + q_point] + = edge_quadrature.point + (QProjector::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 + (i, reference_edge_quadrature.point (q_point) (0), + j); + this->generalized_support_points + [q_point + (i + 4 * j + 2) * n_edge_points] + = Point + (reference_edge_quadrature.point (q_point) (0), + i, j); + this->generalized_support_points + [q_point + (i + 2 * (j + 4)) * n_edge_points] + = Point + (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 (idofs_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 +void +FE_Nedelec::initialize_restriction () { - const unsigned int dim = 3; - Assert (idofs_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::lines_per_cell * this->degree; + const unsigned int n_dofs + = (GeometryInfo::lines_per_cell + 2 * deg) * this->degree; + + for (unsigned int ref = RefinementCase::cut_x; + ref <= RefinementCase::isotropic_refinement; ++ref) + { + const unsigned int index = ref - 1; + + switch (ref) + { + case RefinementCase::cut_x: + { + for (unsigned int child = 0; + child + < GeometryInfo::n_children + (RefinementCase (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::cut_y: + { + for (unsigned int child = 0; + child + < GeometryInfo::n_children + (RefinementCase (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::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::n_children + (RefinementCase (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::lines_per_cell * deg; + const unsigned int n_boundary_dofs + = n_edge_dofs + + 2 * GeometryInfo::faces_per_cell * deg * this->degree; + const unsigned int n_dofs + = (GeometryInfo::lines_per_cell + + (2 * GeometryInfo::faces_per_cell + 3 * deg) * deg) + * this->degree; + + for (unsigned int ref = RefinementCase::cut_x; + ref <= RefinementCase::isotropic_refinement; ++ref) + { + const unsigned int index = ref - 1; + + switch (ref) + { + case RefinementCase<3>::cut_x: + { + for (unsigned int child = 0; + child + < GeometryInfo::n_children + (RefinementCase (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::n_children + (RefinementCase (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::n_children + (RefinementCase (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::n_children + (RefinementCase (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::n_children + (RefinementCase (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::n_children + (RefinementCase (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::n_children + (RefinementCase (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 +FE_Nedelec<1>::get_dpo_vector (const unsigned int degree) { - const unsigned int dim = 2; - Assert (idofs_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 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 +std::vector +FE_Nedelec::get_dpo_vector (const unsigned int degree) { - const unsigned int dim = 3; - Assert (idofs_per_cell, ExcIndexRange(i,0,this->dofs_per_cell)); - Assert (component < dim, ExcIndexRange (component, 0, dim)); + std::vector 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 -void -FE_Nedelec::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 +bool +FE_Nedelec::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 (degreeinterface_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::faces_per_cell, + ExcIndexRange (face_index, 0, GeometryInfo::faces_per_cell)); -template -void -FE_Nedelec::initialize_embedding () -{ - unsigned int iso=RefinementCase::isotropic_refinement-1; - if ((degree < Matrices::n_embedding_matrices+1) && - (Matrices::embedding[degree-1][0] != 0)) - for (unsigned int c=0; c::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; rowdofs_per_cell; ++row) + switch (dim) + { + case 2: + switch (face_index) { - double sum = 0; - for (unsigned int col=0; coldofs_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 -void -FE_Nedelec::initialize_restriction () -{ - unsigned int iso=RefinementCase::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::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::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 -void FE_Nedelec::initialize_unit_support_points () +template +bool +FE_Nedelec::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::lines_per_cell); - for (unsigned int line=0; line::lines_per_cell; ++line) - { - const unsigned int - vertex_index_0 = GeometryInfo::line_to_cell_vertices(line,0), - vertex_index_1 = GeometryInfo::line_to_cell_vertices(line,1); - - const Point - vertex_0 = GeometryInfo::unit_cell_vertex(vertex_index_0), - vertex_1 = GeometryInfo::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 +std::vector > +FE_Nedelec::hp_vertex_dof_identities (const FiniteElement& 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 > (); } -#endif - - -template -void FE_Nedelec::initialize_unit_face_support_points () +template +std::vector > +FE_Nedelec::hp_line_dof_identities (const FiniteElement& 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 *fe_nedelec_other + = dynamic_cast*> (&fe_other)) { - case 1: - { - // do this the same as above, but - // for one dimension less - this->unit_face_support_points.resize(GeometryInfo::lines_per_cell); - for (unsigned int line=0; line::lines_per_cell; ++line) - { - const unsigned int - vertex_index_0 = GeometryInfo::line_to_cell_vertices(line,0), - vertex_index_1 = GeometryInfo::line_to_cell_vertices(line,1); - - const Point - vertex_0 = GeometryInfo::unit_cell_vertex(vertex_index_0), - vertex_1 = GeometryInfo::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 > 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 -std::vector -FE_Nedelec::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 dpo(dim+1, 0U); - dpo[1] = degree; - - return dpo; + else + if (dynamic_cast*> (&fe_other) != 0) + { + // the FE_Nothing has no + // degrees of freedom, so there + // are no equivalencies to be + // recorded + return std::vector > (); + } + + else + { + Assert (false, ExcNotImplemented ()); + return std::vector > (); + } } - - -template -UpdateFlags -FE_Nedelec::update_once (const UpdateFlags) const +template +std::vector > +FE_Nedelec::hp_quad_dof_identities (const FiniteElement& 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 -UpdateFlags -FE_Nedelec::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 *fe_nedelec_other + = dynamic_cast*> (&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 > 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*> (&fe_other) != 0) + { + // the FE_Nothing has no + // degrees of freedom, so there + // are no equivalencies to be + // recorded + return std::vector > (); + } + + else + { + Assert (false, ExcNotImplemented ()); + return std::vector > (); + } } - - -//--------------------------------------------------------------------------- -// Data field initialization -//--------------------------------------------------------------------------- - -template -typename Mapping::InternalDataBase * -FE_Nedelec::get_data (const UpdateFlags update_flags, - const Mapping &mapping, - const Quadrature &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 +void +FE_Nedelec::get_face_interpolation_matrix + (const FiniteElement& source, FullMatrix& 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 > (n_q_points)); - - if (flags & update_gradients) - data->shape_gradients.resize (this->dofs_per_cell, - std::vector > (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; idofs_per_cell; ++i) - for (unsigned int q=0; qshape_values[i][q][c] - = shape_value_component(i,quadrature.point(q),c); - - if (flags & update_gradients) - for (unsigned int c=0; cshape_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 FEN; + typedef FiniteElement FEL; + + AssertThrow ((source.get_name ().find ("FE_Nedelec<") == 0) || + (dynamic_cast (&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 &source_fe + = dynamic_cast&> (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::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 +template void -FE_Nedelec::fill_fe_values - (const Mapping &mapping, - const typename Triangulation::cell_iterator &cell, - const Quadrature &quadrature, - typename Mapping::InternalDataBase &mapping_data, - typename Mapping::InternalDataBase &fedata, - FEValuesData &data, - CellSimilarity::Similarity &/*cell_similarity*/) const +FE_Nedelec::get_subface_interpolation_matrix + (const FiniteElement& source, const unsigned int subface, + FullMatrix& interpolation_matrix) const { - // convert data object to internal - // data for this class. fails with - // an exception if that is not - // possible - Assert (dynamic_cast (&fedata) != 0, - ExcInternalError()); - InternalData &fe_data = static_cast (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 > 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; kdofs_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 > shape_grads1 (n_q_points); - std::vector > 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; kdofs_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; qcompute_2nd (mapping, cell, - QProjector::DataSetDescriptor::cell(), - mapping_data, fe_data, data); + Assert (false, ExcNotImplemented ()); } - - -template +#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 void -FE_Nedelec::fill_fe_face_values (const Mapping &mapping, - const typename Triangulation::cell_iterator &cell, - const unsigned int face, - const Quadrature &quadrature, - typename Mapping::InternalDataBase &mapping_data, - typename Mapping::InternalDataBase &fedata, - FEValuesData &data) const +FE_Nedelec::get_subface_interpolation_matrix + (const FiniteElement& source, const unsigned int subface, + FullMatrix& 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 (fedata); - - // offset determines which data set - // to take (all data sets for all - // faces are stored contiguously) - const typename QProjector::DataSetDescriptor offset - = (QProjector::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::faces_per_cell * n_q_points * - (dim == 3 ? 8 : 1), - ExcInternalError()); - - std::vector > 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; kdofs_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 FEN; + typedef FiniteElement FEL; + + AssertThrow ((source.get_name ().find ("FE_Nedelec<") == 0) || + (dynamic_cast (&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 &source_fe + = dynamic_cast&> (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::faces_per_cell * n_q_points * - (dim == 3 ? 8 : 1), - ExcInternalError()); - - std::vector > shape_grads1 (n_q_points); - std::vector > 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; kdofs_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 reference_edge_quadrature (this->degree); + const Quadrature& edge_quadrature + = QProjector::project_to_child + (reference_edge_quadrature, subface); + const unsigned int& n_edge_points = edge_quadrature.size (); + const std::vector >& + 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 (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 >& + lobatto_polynomials + = Polynomials::Lobatto::generate_complete_basis + (this->degree); + FullMatrix assembling_matrix (deg, n_edge_points); + std::vector > + 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 system_matrix (deg, deg); + + assembling_matrix.mTmult (system_matrix, assembling_matrix); + + FullMatrix system_matrix_inv (deg, deg); + + system_matrix_inv.invert (system_matrix); + + Vector solution (deg); + Vector 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 (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 -void -FE_Nedelec::fill_fe_subface_values (const Mapping &mapping, - const typename Triangulation::cell_iterator &cell, - const unsigned int face, - const unsigned int subface, - const Quadrature &quadrature, - typename Mapping::InternalDataBase &mapping_data, - typename Mapping::InternalDataBase &fedata, - FEValuesData &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 (fedata); - - // offset determines which data set - // to take (all data sets for all - // faces are stored contiguously) - const typename QProjector::DataSetDescriptor offset - = (QProjector::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::max_children_per_face * - GeometryInfo::faces_per_cell * - n_q_points, - ExcInternalError()); - - std::vector > shape_values (n_q_points); + case 3: + { + const QGauss 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; kdofs_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::faces_per_cell * - GeometryInfo::max_children_per_face * - n_q_points, - ExcInternalError()); - - std::vector > shape_grads1 (n_q_points); - std::vector > 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; kdofs_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& edge_quadrature + = QProjector::project_to_child + (reference_edge_quadrature, 0); + const unsigned int n_edge_points = edge_quadrature.size (); + const std::vector >& + 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 + (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 + (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 reference_face_quadrature + (this->degree); + const Quadrature& face_quadrature + = QProjector::project_to_child + (reference_face_quadrature, 0); + const std::vector >& + legendre_polynomials + = Polynomials::Legendre::generate_complete_basis + (deg); + const std::vector >& + lobatto_polynomials + = Polynomials::Lobatto::generate_complete_basis + (this->degree); + const std::vector >& + face_quadrature_points = face_quadrature.get_points (); + const unsigned int& n_face_points + = face_quadrature.size (); + FullMatrix assembling_matrix + (deg, n_edge_points); + FullMatrix system_matrix (deg, deg); + FullMatrix system_matrix_inv (deg, deg); + std::vector > + 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 > > + edge_quadrature_points_full_dim + (GeometryInfo::lines_per_face); + + for (unsigned int line = 0; + line < GeometryInfo::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 (0.0, + edge_quadrature_points[q_point] (0), + 0.0); + edge_quadrature_points_full_dim[1][q_point] + = Point (0.5, + edge_quadrature_points[q_point] (0), + 0.0); + edge_quadrature_points_full_dim[2][q_point] + = Point (edge_quadrature_points[q_point] (0), + 0.0, 0.0); + edge_quadrature_points_full_dim[3][q_point] + = Point (edge_quadrature_points[q_point] (0), + 0.5, 0.0); + } + + Vector solution (deg); + Vector 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::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 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 + (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 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 + (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& edge_quadrature_x + = QProjector::project_to_child + (reference_edge_quadrature, 1); + const Quadrature& edge_quadrature_y + = QProjector::project_to_child + (reference_edge_quadrature, 0); + const std::vector >& + edge_quadrature_x_points = edge_quadrature_x.get_points (); + const std::vector >& + 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 + (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 + (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 reference_face_quadrature + (this->degree); + const Quadrature& face_quadrature + = QProjector::project_to_child + (reference_face_quadrature, 1); + const std::vector >& + face_quadrature_points = face_quadrature.get_points (); + const std::vector >& + legendre_polynomials + = Polynomials::Legendre::generate_complete_basis + (deg); + const std::vector >& + lobatto_polynomials + = Polynomials::Lobatto::generate_complete_basis + (this->degree); + const unsigned int& + n_face_points = face_quadrature.size (); + FullMatrix assembling_matrix (deg, + n_edge_points); + FullMatrix system_matrix (deg, deg); + FullMatrix system_matrix_inv (deg, deg); + std::vector > + 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 > edge_quadrature_points + (GeometryInfo::lines_per_face); + std::vector > + edge_quadrature_weights + (GeometryInfo::lines_per_face); + std::vector > > + edge_quadrature_points_full_dim + (GeometryInfo::lines_per_face); + + for (unsigned int line = 0; + line < GeometryInfo::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 + (0.5, edge_quadrature_y_points[q_point] (0), + 0.0); + edge_quadrature_points_full_dim[1][q_point] + = Point + (1.0, edge_quadrature_y_points[q_point] (0), + 0.0); + edge_quadrature_points_full_dim[2][q_point] + = Point + (edge_quadrature_x_points[q_point] (0), 0.0, + 0.0); + edge_quadrature_points_full_dim[3][q_point] + = Point + (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 system_rhs (system_matrix.m ()); + Vector 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::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 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 + (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 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 + (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& edge_quadrature_x + = QProjector::project_to_child + (reference_edge_quadrature, 0); + const Quadrature& edge_quadrature_y + = QProjector::project_to_child + (reference_edge_quadrature, 1); + const unsigned int& n_edge_points + = edge_quadrature_x.size (); + const std::vector >& + edge_quadrature_x_points = edge_quadrature_x.get_points (); + const std::vector >& + 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 + (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 + (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 reference_face_quadrature (this->degree); + const Quadrature& face_quadrature + = QProjector::project_to_child + (reference_face_quadrature, 2); + const std::vector >& + face_quadrature_points = face_quadrature.get_points (); + const std::vector >& legendre_polynomials + = Polynomials::Legendre::generate_complete_basis (deg); + const std::vector >& lobatto_polynomials + = Polynomials::Lobatto::generate_complete_basis (this->degree); + const unsigned int& n_face_points + = face_quadrature.size (); + FullMatrix assembling_matrix (deg, + n_edge_points); + FullMatrix system_matrix (deg, deg); + FullMatrix system_matrix_inv (deg, deg); + std::vector > + 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 > + edge_quadrature_points + (GeometryInfo::lines_per_face); + std::vector > + edge_quadrature_weights + (GeometryInfo::lines_per_face); + std::vector > > + edge_quadrature_points_full_dim + (GeometryInfo::lines_per_face); + + for (unsigned int line = 0; + line < GeometryInfo::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 + (0.0, edge_quadrature_y_points[q_point] (0), + 0.0); + edge_quadrature_points_full_dim[1][q_point] + = Point + (0.5, edge_quadrature_y_points[q_point] (0), + 0.0); + edge_quadrature_points_full_dim[2][q_point] + = Point + (edge_quadrature_x_points[q_point] (0), 0.5, + 0.0); + edge_quadrature_points_full_dim[3][q_point] + = Point + (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 system_rhs (system_matrix.m ()); + Vector 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::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 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 + (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 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 + (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& edge_quadrature + = QProjector::project_to_child + (reference_edge_quadrature, 1); + const unsigned int& n_edge_points = edge_quadrature.size (); + const std::vector >& + 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 + (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 + (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 + reference_face_quadrature (this->degree); + const Quadrature& face_quadrature + = QProjector::project_to_child + (reference_face_quadrature, 3); + const std::vector >& + face_quadrature_points = face_quadrature.get_points (); + const std::vector >& + legendre_polynomials + = Polynomials::Legendre::generate_complete_basis + (deg); + const std::vector >& + lobatto_polynomials + = Polynomials::Lobatto::generate_complete_basis + (this->degree); + const unsigned int& n_face_points + = face_quadrature.size (); + FullMatrix assembling_matrix (deg, + n_edge_points); + FullMatrix system_matrix (deg, deg); + FullMatrix system_matrix_inv (deg, deg); + std::vector > + 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 > > + edge_quadrature_points_full_dim + (GeometryInfo::lines_per_face); + + for (unsigned int line = 0; + line < GeometryInfo::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 + (0.5, edge_quadrature_points[q_point] (0), 0.0); + edge_quadrature_points_full_dim[1][q_point] + = Point + (1.0, edge_quadrature_points[q_point] (0), 0.0); + edge_quadrature_points_full_dim[2][q_point] + = Point (edge_quadrature_points[q_point] (0), + 0.5, 0.0); + edge_quadrature_points_full_dim[3][q_point] + = Point (edge_quadrature_points[q_point] (0), + 1.0, 0.0); + } + + Vector system_rhs (system_matrix.m ()); + Vector 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::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 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 + (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 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 + (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; qcompute_2nd (mapping, cell, offset, mapping_data, fe_data, data); } +#endif - -template -unsigned int -FE_Nedelec::n_base_elements () const -{ - return 1; -} - - - -template -const FiniteElement & -FE_Nedelec::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 +void FE_Nedelec::interpolate (std::vector&, const std::vector&) const { + Assert(false, ExcNotImplemented ()); } - -template -unsigned int -FE_Nedelec::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 +void +FE_Nedelec::interpolate (std::vector& local_dofs, + const std::vector >& 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 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 >& + 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 > + 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 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 system_matrix_inv (deg, deg); + + system_matrix_inv.invert (system_matrix); + + Vector system_rhs (system_matrix.m ()); + Vector solution (system_rhs.size ()); + + for (unsigned int line = 0; + line < GeometryInfo::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 reference_quadrature (this->degree); + const std::vector >& + 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::lines_per_cell + * n_edge_points] + (0)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points] + (1)) + * lobatto_polynomials_grad[k].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points] + (0)) + * lobatto_polynomials[l + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::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::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::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::lines_per_cell + * n_edge_points] + (0)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::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::lines_per_cell) + * deg + j + + GeometryInfo::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::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::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::lines_per_cell + * n_edge_points] + (1)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::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::lines_per_cell + + deg) * this->degree] + = solution (i * deg + j); + } + + break; + } + + case 3: + { + const QGauss + 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 >& + 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 system_matrix (deg, deg); + FullMatrix system_matrix_inv (deg, deg); + std::vector > + 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 system_rhs (system_matrix.m ()); + Vector 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::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 >& + 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::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::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::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::lines_per_cell) + * deg + j + + GeometryInfo::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::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::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::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::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::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::lines_per_cell + + 2 * this->degree) * deg + j + + GeometryInfo::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::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::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::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::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::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::lines_per_cell + + 4 * this->degree) * deg + + j + + GeometryInfo::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::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::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::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::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::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::lines_per_cell + + 6 * this->degree) * deg + j + + GeometryInfo::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::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::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::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::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::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::lines_per_cell + + 8 * this->degree) * deg + + j + + GeometryInfo::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::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::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::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::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::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::lines_per_cell + + 10 * this->degree) + * deg + j + + GeometryInfo::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::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::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::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 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::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (0)) * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (1)) + * lobatto_polynomials[k + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (2)) + * lobatto_polynomials_grad[l].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (0)) + * lobatto_polynomials[m + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (1)) + * lobatto_polynomials[n + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell) + * deg + j + + GeometryInfo::lines_per_cell] + * this->shape_value_component + ((i + 2 * (k + 2) * this->degree + + GeometryInfo::lines_per_cell) + * deg + j + + GeometryInfo::lines_per_cell, + this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (0)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (1)) + * lobatto_polynomials[k + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::faces_per_cell) + * deg + j + + GeometryInfo::lines_per_cell + + 2 + * GeometryInfo::faces_per_cell) + * deg + k + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points], + 1); + + for (unsigned int k = 0; k < deg; ++k) + tmp -= local_dofs[(i + 2 * j * this->degree + + GeometryInfo::lines_per_cell) + * deg + k + + GeometryInfo::lines_per_cell] + * this->shape_value_component + ((i + 2 * j * this->degree + + GeometryInfo::lines_per_cell) + * deg + k + + GeometryInfo::lines_per_cell, + this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points], + 1) + + local_dofs[i + ((2 * j + 9) * deg + k + + GeometryInfo::lines_per_cell) + * this->degree] + * this->shape_value_component + (i + ((2 * j + 9) * deg + k + + GeometryInfo::lines_per_cell) + * this->degree, + this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (1)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (0)) + * lobatto_polynomials[k + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::faces_per_cell) + * deg + j + + GeometryInfo::lines_per_cell + 2 + * GeometryInfo::faces_per_cell) + * deg + k + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell) + * this->degree] + * this->shape_value_component + (i + ((2 * j + 1) * deg + k + + GeometryInfo::lines_per_cell) + * this->degree, + this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (2)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (0)) + * lobatto_polynomials[k + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::faces_per_cell)) + * deg + k + + GeometryInfo::lines_per_cell) + * this->degree] + = solution ((i * deg + j) * deg + k); + } + + break; + } + + default: + Assert (false, ExcNotImplemented ()); + } } - -template -bool -FE_Nedelec::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 +void +FE_Nedelec::interpolate (std::vector& local_dofs, + const VectorSlice > >& values) +const { - Assert (shape_index < this->dofs_per_cell, - ExcIndexRange (shape_index, 0, this->dofs_per_cell)); - Assert (face_index < GeometryInfo::faces_per_cell, - ExcIndexRange (face_index, 0, GeometryInfo::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 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 >& + lobatto_polynomials + = Polynomials::Lobatto::generate_complete_basis + (this->degree); + FullMatrix system_matrix (deg, deg); + std::vector > + 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 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 system_rhs (system_matrix.m ()); + Vector solution (system_rhs.size ()); + + for (unsigned int line = 0; + line < GeometryInfo::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 reference_quadrature (this->degree); + const unsigned int& + n_interior_points = reference_quadrature.size (); + const std::vector >& + 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::lines_per_cell + * n_edge_points] + (0)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points] + (1)) + * lobatto_polynomials_grad[k].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points] + (0)) + * lobatto_polynomials[l + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::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::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::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::lines_per_cell + * n_edge_points] + (0)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::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::lines_per_cell) * deg + + j + GeometryInfo::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::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::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::lines_per_cell + * n_edge_points] + (1)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::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::lines_per_cell + + deg) * this->degree] + = solution (i * deg + j); + } + + break; + } + + case 3: + { + // Let us begin with the + // interpolation part. + const QGauss 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 >& + lobatto_polynomials + = Polynomials::Lobatto::generate_complete_basis + (this->degree); + FullMatrix system_matrix (deg, deg); + std::vector > + 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 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 system_rhs (system_matrix.m ()); + Vector solution (system_rhs.size ()); + + for (unsigned int line = 0; + line < GeometryInfo::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 >& + 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::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::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::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::lines_per_cell) * deg + + j + GeometryInfo::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::lines_per_cell + * n_edge_points]; + + for (unsigned int i = 2; + i < GeometryInfo::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::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::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 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::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (0)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (1)) + * lobatto_polynomials[k + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (2)) + * lobatto_polynomials_grad[l].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (0)) + * lobatto_polynomials[m + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (1)) + * lobatto_polynomials[n + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell) + * deg + j + + GeometryInfo::lines_per_cell] + * this->shape_value_component + ((i + 2 * (k + 2) * this->degree + + GeometryInfo::lines_per_cell) + * deg + j + + GeometryInfo::lines_per_cell, + this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (0)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (1)) + * lobatto_polynomials[k + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::faces_per_cell) + * deg + j + GeometryInfo::lines_per_cell + + 2 * GeometryInfo::faces_per_cell) + * deg + k + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points], + 1); + + for (unsigned int k = 0; k < deg; ++k) + tmp -= local_dofs[(i + 2 * j * this->degree + + GeometryInfo::lines_per_cell) + * deg + k + + GeometryInfo::lines_per_cell] + * this->shape_value_component + ((i + 2 * j * this->degree + + GeometryInfo::lines_per_cell) + * deg + k + + GeometryInfo::lines_per_cell, + this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points], + 1) + + local_dofs[i + ((2 * j + 9) * deg + k + + GeometryInfo::lines_per_cell) + * this->degree] + * this->shape_value_component + (i + ((2 * j + 9) * deg + k + + GeometryInfo::lines_per_cell) + * this->degree, + this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (1)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (0)) + * lobatto_polynomials[k + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::faces_per_cell) * deg + + j + GeometryInfo::lines_per_cell + 2 + * GeometryInfo::faces_per_cell) * deg + + k + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell) + * this->degree] + * this->shape_value_component + (i + ((2 * j + 1) * deg + k + + GeometryInfo::lines_per_cell) + * this->degree, + this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (2)) + * lobatto_polynomials[j + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::faces_per_cell + * n_face_points] + (0)) + * lobatto_polynomials[k + 2].value + (this->generalized_support_points[q_point + + GeometryInfo::lines_per_cell + * n_edge_points + + GeometryInfo::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::faces_per_cell)) + * deg + k + + GeometryInfo::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 +template unsigned int -FE_Nedelec::memory_consumption () const +FE_Nedelec::memory_consumption () const { Assert (false, ExcNotImplemented ()); return 0; } - -template -unsigned int -FE_Nedelec::get_degree () const -{ - return degree; -} - - template class FE_Nedelec; DEAL_II_NAMESPACE_CLOSE - diff --git a/deal.II/deal.II/source/fe/fe_poly_tensor.cc b/deal.II/deal.II/source/fe/fe_poly_tensor.cc index db97ccb8b3..3665e72185 100644 --- a/deal.II/deal.II/source/fe/fe_poly_tensor.cc +++ b/deal.II/deal.II/source/fe/fe_poly_tensor.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -433,6 +434,18 @@ FE_PolyTensor::fill_fe_values ( = sign_change[i] * shape_values[k][d]; break; } + + case mapping_nedelec: { + std::vector > 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::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::fill_fe_face_values ( break; } + case mapping_nedelec: { + std::vector > 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::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::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::update_each (const UpdateFlags flags) const template class FE_PolyTensor,deal_II_dimension>; template class FE_PolyTensor,deal_II_dimension>; template class FE_PolyTensor,deal_II_dimension>; - +template class FE_PolyTensor, deal_II_dimension>; DEAL_II_NAMESPACE_CLOSE