1 // Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #ifndef MFEM_FE
13 #define MFEM_FE
14 
15 #include "../config/config.hpp"
16 #include "../general/array.hpp"
17 #include "../linalg/linalg.hpp"
18 #include "intrules.hpp"
19 #include "geom.hpp"
20 
21 #include <map>
22 
23 namespace mfem
24 {
25 
26 /// Possible basis types. Note that not all elements can use all BasisType(s).
27 class BasisType
28 {
29 public:
30    enum
31    {
32       Invalid         = -1,
33       GaussLegendre   = 0,  ///< Open type
34       GaussLobatto    = 1,  ///< Closed type
35       Positive        = 2,  ///< Bernstein polynomials
36       OpenUniform     = 3,  ///< Nodes: x_i = (i+1)/(n+1), i=0,...,n-1
37       ClosedUniform   = 4,  ///< Nodes: x_i = i/(n-1),     i=0,...,n-1
38       OpenHalfUniform = 5,  ///< Nodes: x_i = (i+1/2)/n,   i=0,...,n-1
39       Serendipity     = 6,  ///< Serendipity basis (squares / cubes)
40       ClosedGL        = 7,  ///< Closed GaussLegendre
41       IntegratedGLL   = 8,  ///< Integrated GLL indicator functions
42       NumBasisTypes   = 9   /**< Keep track of maximum types to prevent
43                                  hard-coding */
44    };
45    /** @brief If the input does not represents a valid BasisType, abort with an
46        error; otherwise return the input. */
Check(int b_type)47    static int Check(int b_type)
48    {
49       MFEM_VERIFY(0 <= b_type && b_type < NumBasisTypes,
50                   "unknown BasisType: " << b_type);
51       return b_type;
52    }
53    /** @brief If the input does not represents a valid nodal BasisType, abort
54        with an error; otherwise return the input. */
CheckNodal(int b_type)55    static int CheckNodal(int b_type)
56    {
57       MFEM_VERIFY(Check(b_type) != Positive && b_type != IntegratedGLL,
58                   "invalid nodal BasisType: " << Name(b_type));
59       return b_type;
60    }
61    /** @brief Get the corresponding Quadrature1D constant, when that makes
62        sense; otherwise return Quadrature1D::Invalid. */
GetQuadrature1D(int b_type)63    static int GetQuadrature1D(int b_type)
64    {
65       switch (b_type)
66       {
67          case GaussLegendre:   return Quadrature1D::GaussLegendre;
68          case GaussLobatto:    return Quadrature1D::GaussLobatto;
69          case Positive:        return Quadrature1D::ClosedUniform; // <-----
70          case OpenUniform:     return Quadrature1D::OpenUniform;
71          case ClosedUniform:   return Quadrature1D::ClosedUniform;
72          case OpenHalfUniform: return Quadrature1D::OpenHalfUniform;
73          case Serendipity:     return Quadrature1D::GaussLobatto;
74          case ClosedGL:        return Quadrature1D::ClosedGL;
75          case IntegratedGLL:   return Quadrature1D::GaussLegendre;
76       }
77       return Quadrature1D::Invalid;
78    }
79    /// Return the nodal BasisType corresponding to the Quadrature1D type.
GetNodalBasis(int qpt_type)80    static int GetNodalBasis(int qpt_type)
81    {
82       switch (qpt_type)
83       {
84          case Quadrature1D::GaussLegendre:   return GaussLegendre;
85          case Quadrature1D::GaussLobatto:    return GaussLobatto;
86          case Quadrature1D::OpenUniform:     return OpenUniform;
87          case Quadrature1D::ClosedUniform:   return ClosedUniform;
88          case Quadrature1D::OpenHalfUniform: return OpenHalfUniform;
89          case Quadrature1D::ClosedGL:        return ClosedGL;
90       }
91       return Invalid;
92    }
93    /// Check and convert a BasisType constant to a string identifier.
Name(int b_type)94    static const char *Name(int b_type)
95    {
96       static const char *name[] =
97       {
98          "Gauss-Legendre", "Gauss-Lobatto", "Positive (Bernstein)",
99          "Open uniform", "Closed uniform", "Open half uniform",
100          "Serendipity", "Closed Gauss-Legendre",
101          "Integrated Gauss-Lobatto indicator"
102       };
103       return name[Check(b_type)];
104    }
105    /// Check and convert a BasisType constant to a char basis identifier.
GetChar(int b_type)106    static char GetChar(int b_type)
107    {
108       static const char ident[]
109          = { 'g', 'G', 'P', 'u', 'U', 'o', 'S', 'c', 'i' };
110       return ident[Check(b_type)];
111    }
112    /// Convert char basis identifier to a BasisType constant.
GetType(char b_ident)113    static int GetType(char b_ident)
114    {
115       switch (b_ident)
116       {
117          case 'g': return GaussLegendre;
118          case 'G': return GaussLobatto;
119          case 's': return GaussLobatto;
120          case 'P': return Positive;
121          case 'u': return OpenUniform;
122          case 'U': return ClosedUniform;
123          case 'o': return OpenHalfUniform;
124          case 'S': return Serendipity;
125          case 'c': return ClosedGL;
126          case 'i': return IntegratedGLL;
127       }
128       MFEM_ABORT("unknown BasisType identifier");
129       return -1;
130    }
131 };
132 
133 
134 /** @brief Structure representing the matrices/tensors needed to evaluate (in
135     reference space) the values, gradients, divergences, or curls of a
136     FiniteElement at a the quadrature points of a given IntegrationRule. */
137 /** Object of this type are typically created and owned by the respective
138     FiniteElement object. */
139 class DofToQuad
140 {
141 public:
142    /// The FiniteElement that created and owns this object.
143    /** This pointer is not owned. */
144    const class FiniteElement *FE;
145 
146    /** @brief IntegrationRule that defines the quadrature points at which the
147        basis functions of the #FE are evaluated. */
148    /** This pointer is not owned. */
149    const IntegrationRule *IntRule;
150 
151    /// Type of data stored in the arrays #B, #Bt, #G, and #Gt.
152    enum Mode
153    {
154       /** @brief Full multidimensional representation which does not use tensor
155           product structure. The ordering of the degrees of freedom is as
156           defined by #FE */
157       FULL,
158 
159       /** @brief Tensor product representation using 1D matrices/tensors with
160           dimensions using 1D number of quadrature points and degrees of
161           freedom. */
162       /** When representing a vector-valued FiniteElement, two DofToQuad objects
163           are used to describe the "closed" and "open" 1D basis functions
164           (TODO). */
165       TENSOR
166    };
167 
168    /// Describes the contents of the #B, #Bt, #G, and #Gt arrays, see #Mode.
169    Mode mode;
170 
171    /** @brief Number of degrees of freedom = number of basis functions. When
172        #mode is TENSOR, this is the 1D number. */
173    int ndof;
174 
175    /** @brief Number of quadrature points. When #mode is TENSOR, this is the 1D
176        number. */
177    int nqpt;
178 
179    /// Basis functions evaluated at quadrature points.
180    /** The storage layout is column-major with dimensions:
181        - #nqpt x #ndof, for scalar elements, or
182        - #nqpt x dim x #ndof, for vector elements, (TODO)
183 
184        where
185 
186        - dim = dimension of the finite element reference space when #mode is
187          FULL, and dim = 1 when #mode is TENSOR. */
188    Array<double> B;
189 
190    /// Transpose of #B.
191    /** The storage layout is column-major with dimensions:
192        - #ndof x #nqpt, for scalar elements, or
193        - #ndof x #nqpt x dim, for vector elements (TODO). */
194    Array<double> Bt;
195 
196    /** @brief Gradients/divergences/curls of basis functions evaluated at
197        quadrature points. */
198    /** The storage layout is column-major with dimensions:
199        - #nqpt x dim x #ndof, for scalar elements, or
200        - #nqpt x #ndof, for H(div) vector elements (TODO), or
201        - #nqpt x cdim x #ndof, for H(curl) vector elements (TODO),
202 
203        where
204 
205        - dim = dimension of the finite element reference space when #mode is
206          FULL, and 1 when #mode is TENSOR,
207        - cdim = 1/1/3 in 1D/2D/3D, respectively, when #mode is FULL, and cdim =
208          1 when #mode is TENSOR. */
209    Array<double> G;
210 
211    /// Transpose of #G.
212    /** The storage layout is column-major with dimensions:
213        - #ndof x #nqpt x dim, for scalar elements, or
214        - #ndof x #nqpt, for H(div) vector elements (TODO), or
215        - #ndof x #nqpt x cdim, for H(curl) vector elements (TODO). */
216    Array<double> Gt;
217 };
218 
219 
220 /// Describes the function space on each element
221 class FunctionSpace
222 {
223 public:
224    enum
225    {
226       Pk, ///< Polynomials of order k
227       Qk, ///< Tensor products of polynomials of order k
228       rQk ///< Refined tensor products of polynomials of order k
229    };
230 };
231 
232 class ElementTransformation;
233 class Coefficient;
234 class VectorCoefficient;
235 class MatrixCoefficient;
236 class KnotVector;
237 
238 
239 // Base and derived classes for finite elements
240 
241 
242 /// Abstract class for all finite elements.
243 class FiniteElement
244 {
245 protected:
246    int dim;      ///< Dimension of reference space
247    Geometry::Type geom_type; ///< Geometry::Type of the reference element
248    int func_space, range_type, map_type,
249        deriv_type, deriv_range_type, deriv_map_type;
250    mutable
251    int dof,      ///< Number of degrees of freedom
252        order;    ///< Order/degree of the shape functions
253    mutable int orders[Geometry::MaxDim]; ///< Anisotropic orders
254    IntegrationRule Nodes;
255 #ifndef MFEM_THREAD_SAFE
256    mutable DenseMatrix vshape; // Dof x Dim
257 #endif
258    /// Container for all DofToQuad objects created by the FiniteElement.
259    /** Multiple DofToQuad objects may be needed when different quadrature rules
260        or different DofToQuad::Mode are used. */
261    mutable Array<DofToQuad*> dof2quad_array;
262 
263 public:
264    /// Enumeration for range_type and deriv_range_type
265    enum RangeType { SCALAR, VECTOR };
266 
267    /** @brief Enumeration for MapType: defines how reference functions are
268        mapped to physical space.
269 
270        A reference function \f$ \hat u(\hat x) \f$ can be mapped to a function
271       \f$ u(x) \f$ on a general physical element in following ways:
272        - \f$ x = T(\hat x) \f$ is the image of the reference point \f$ \hat x \f$
273        - \f$ J = J(\hat x) \f$ is the Jacobian matrix of the transformation T
274        - \f$ w = w(\hat x) = det(J) \f$ is the transformation weight factor for square J
275        - \f$ w = w(\hat x) = det(J^t J)^{1/2} \f$ is the transformation weight factor in general
276    */
277    enum MapType
278    {
279       VALUE,     /**< For scalar fields; preserves point values
280                           \f$ u(x) = \hat u(\hat x) \f$ */
281       INTEGRAL,  /**< For scalar fields; preserves volume integrals
282                           \f$ u(x) = (1/w) \hat u(\hat x) \f$ */
283       H_DIV,     /**< For vector fields; preserves surface integrals of the
284                           normal component \f$ u(x) = (J/w) \hat u(\hat x) \f$ */
285       H_CURL     /**< For vector fields; preserves line integrals of the
286                           tangential component
287                           \f$ u(x) = J^{-t} \hat u(\hat x) \f$ (square J),
288                           \f$ u(x) = J(J^t J)^{-1} \hat u(\hat x) \f$ (general J) */
289    };
290 
291    /** @brief Enumeration for DerivType: defines which derivative method
292        is implemented.
293 
294        Each FiniteElement class implements up to one type of derivative.  The
295        value returned by GetDerivType() indicates which derivative method is
296        implemented.
297    */
298    enum DerivType
299    {
300       NONE, ///< No derivatives implemented
301       GRAD, ///< Implements CalcDShape methods
302       DIV,  ///< Implements CalcDivShape methods
303       CURL  ///< Implements CalcCurlShape methods
304    };
305 
306    /** @brief Construct FiniteElement with given
307        @param D    Reference space dimension
308        @param G    Geometry type (of type Geometry::Type)
309        @param Do   Number of degrees of freedom in the FiniteElement
310        @param O    Order/degree of the FiniteElement
311        @param F    FunctionSpace type of the FiniteElement
312     */
313    FiniteElement(int D, Geometry::Type G, int Do, int O,
314                  int F = FunctionSpace::Pk);
315 
316    /// Returns the reference space dimension for the finite element
GetDim() const317    int GetDim() const { return dim; }
318 
319    /// Returns the Geometry::Type of the reference element
GetGeomType() const320    Geometry::Type GetGeomType() const { return geom_type; }
321 
322    /// Returns the number of degrees of freedom in the finite element
GetDof() const323    int GetDof() const { return dof; }
324 
325    /** @brief Returns the order of the finite element. In the case of
326        anisotropic orders, returns the maximum order. */
GetOrder() const327    int GetOrder() const { return order; }
328 
329    /** @brief Returns true if the FiniteElement basis *may be using* different
330        orders/degrees in different spatial directions. */
HasAnisotropicOrders() const331    bool HasAnisotropicOrders() const { return orders[0] != -1; }
332 
333    /// Returns an array containing the anisotropic orders/degrees.
GetAnisotropicOrders() const334    const int *GetAnisotropicOrders() const { return orders; }
335 
336    /// Returns the type of FunctionSpace on the element.
Space() const337    int Space() const { return func_space; }
338 
339    /// Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}.
GetRangeType() const340    int GetRangeType() const { return range_type; }
341 
342    /** @brief Returns the FiniteElement::RangeType of the element derivative, either
343        SCALAR or VECTOR. */
GetDerivRangeType() const344    int GetDerivRangeType() const { return deriv_range_type; }
345 
346    /** @brief Returns the FiniteElement::MapType of the element describing how reference
347        functions are mapped to physical space, one of {VALUE, INTEGRAL
348        H_DIV, H_CURL}. */
GetMapType() const349    int GetMapType() const { return map_type; }
350 
351 
352    /** @brief Returns the FiniteElement::DerivType of the element describing the
353        spatial derivative method implemented, one of {NONE, GRAD,
354        DIV, CURL}. */
GetDerivType() const355    int GetDerivType() const { return deriv_type; }
356 
357    /** @brief Returns the FiniteElement::DerivType of the element describing how
358        reference function derivatives are mapped to physical space, one of {VALUE,
359        INTEGRAL, H_DIV, H_CURL}. */
GetDerivMapType() const360    int GetDerivMapType() const { return deriv_map_type; }
361 
362    /** @brief Evaluate the values of all shape functions of a scalar finite
363        element in reference space at the given point @a ip. */
364    /** The size (#dof) of the result Vector @a shape must be set in advance. */
365    virtual void CalcShape(const IntegrationPoint &ip,
366                           Vector &shape) const = 0;
367 
368    /** @brief Evaluate the values of all shape functions of a scalar finite
369        element in physical space at the point described by @a Trans. */
370    /** The size (#dof) of the result Vector @a shape must be set in advance. */
371    void CalcPhysShape(ElementTransformation &Trans, Vector &shape) const;
372 
373    /** @brief Evaluate the gradients of all shape functions of a scalar finite
374        element in reference space at the given point @a ip. */
375    /** Each row of the result DenseMatrix @a dshape contains the derivatives of
376        one shape function. The size (#dof x #dim) of @a dshape must be set in
377        advance.  */
378    virtual void CalcDShape(const IntegrationPoint &ip,
379                            DenseMatrix &dshape) const = 0;
380 
381    /** @brief Evaluate the gradients of all shape functions of a scalar finite
382        element in physical space at the point described by @a Trans. */
383    /** Each row of the result DenseMatrix @a dshape contains the derivatives of
384        one shape function. The size (#dof x SDim) of @a dshape must be set in
385        advance, where SDim >= #dim is the physical space dimension as described
386        by @a Trans. */
387    void CalcPhysDShape(ElementTransformation &Trans, DenseMatrix &dshape) const;
388 
389    /// Get a const reference to the nodes of the element
GetNodes() const390    const IntegrationRule & GetNodes() const { return Nodes; }
391 
392    // virtual functions for finite elements on vector spaces
393 
394    /** @brief Evaluate the values of all shape functions of a *vector* finite
395        element in reference space at the given point @a ip. */
396    /** Each row of the result DenseMatrix @a shape contains the components of
397        one vector shape function. The size (#dof x #dim) of @a shape must be set
398        in advance. */
399    virtual void CalcVShape(const IntegrationPoint &ip,
400                            DenseMatrix &shape) const;
401 
402    /** @brief Evaluate the values of all shape functions of a *vector* finite
403        element in physical space at the point described by @a Trans. */
404    /** Each row of the result DenseMatrix @a shape contains the components of
405        one vector shape function. The size (#dof x SDim) of @a shape must be set
406        in advance, where SDim >= #dim is the physical space dimension as
407        described by @a Trans. */
408    virtual void CalcVShape(ElementTransformation &Trans,
409                            DenseMatrix &shape) const;
410 
411    /// Equivalent to the CalcVShape() method with the same arguments.
CalcPhysVShape(ElementTransformation & Trans,DenseMatrix & shape) const412    void CalcPhysVShape(ElementTransformation &Trans, DenseMatrix &shape) const
413    { CalcVShape(Trans, shape); }
414 
415    /** @brief Evaluate the divergence of all shape functions of a *vector*
416        finite element in reference space at the given point @a ip. */
417    /** The size (#dof) of the result Vector @a divshape must be set in advance.
418     */
419    virtual void CalcDivShape(const IntegrationPoint &ip,
420                              Vector &divshape) const;
421 
422    /** @brief Evaluate the divergence of all shape functions of a *vector*
423        finite element in physical space at the point described by @a Trans. */
424    /** The size (#dof) of the result Vector @a divshape must be set in advance.
425     */
426    void CalcPhysDivShape(ElementTransformation &Trans, Vector &divshape) const;
427 
428    /** @brief Evaluate the curl of all shape functions of a *vector* finite
429        element in reference space at the given point @a ip. */
430    /** Each row of the result DenseMatrix @a curl_shape contains the components
431        of the curl of one vector shape function. The size (#dof x CDim) of
432        @a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
433        CDim = 1 for #dim = 2. */
434    virtual void CalcCurlShape(const IntegrationPoint &ip,
435                               DenseMatrix &curl_shape) const;
436 
437    /** @brief Evaluate the curl of all shape functions of a *vector* finite
438        element in physical space at the point described by @a Trans. */
439    /** Each row of the result DenseMatrix @a curl_shape contains the components
440        of the curl of one vector shape function. The size (#dof x CDim) of
441        @a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
442        CDim = 1 for #dim = 2. */
443    void CalcPhysCurlShape(ElementTransformation &Trans,
444                           DenseMatrix &curl_shape) const;
445 
446    /** @brief Get the dofs associated with the given @a face.
447        @a *dofs is set to an internal array of the local dofc on the
448        face, while *ndofs is set to the number of dofs on that face.
449    */
450    virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
451 
452    /** @brief Evaluate the Hessians of all shape functions of a scalar finite
453        element in reference space at the given point @a ip. */
454    /** Each row of the result DenseMatrix @a Hessian contains upper triangular
455        part of the Hessian of one shape function.
456        The order in 2D is {u_xx, u_xy, u_yy}.
457        The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
458    virtual void CalcHessian (const IntegrationPoint &ip,
459                              DenseMatrix &Hessian) const;
460 
461    /** @brief Evaluate the Hessian of all shape functions of a scalar finite
462        element in reference space at the given point @a ip. */
463    /** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
464    virtual void CalcPhysHessian(ElementTransformation &Trans,
465                                 DenseMatrix& Hessian) const;
466 
467    /** @brief Evaluate the Laplacian of all shape functions of a scalar finite
468        element in reference space at the given point @a ip. */
469    /** The size (#dof) of @a Laplacian must be set in advance. */
470    virtual void CalcPhysLaplacian(ElementTransformation &Trans,
471                                   Vector& Laplacian) const;
472 
473    virtual void CalcPhysLinLaplacian(ElementTransformation &Trans,
474                                      Vector& Laplacian) const;
475 
476    /** @brief Return the local interpolation matrix @a I (Dof x Dof) where the
477        fine element is the image of the base geometry under the given
478        transformation. */
479    virtual void GetLocalInterpolation(ElementTransformation &Trans,
480                                       DenseMatrix &I) const;
481 
482    /** @brief Return a local restriction matrix @a R (Dof x Dof) mapping fine
483        dofs to coarse dofs.
484 
485        The fine element is the image of the base geometry under the given
486        transformation, @a Trans.
487 
488        The assumption in this method is that a subset of the coarse dofs can be
489        expressed only in terms of the dofs of the given fine element.
490 
491        Rows in @a R corresponding to coarse dofs that cannot be expressed in
492        terms of the fine dofs will be marked as invalid by setting the first
493        entry (column 0) in the row to infinity().
494 
495        This method assumes that the dimensions of @a R are set before it is
496        called. */
497    virtual void GetLocalRestriction(ElementTransformation &Trans,
498                                     DenseMatrix &R) const;
499 
500    /** @brief Return interpolation matrix, @a I, which maps dofs from a coarse
501        element, @a fe, to the fine dofs on @a this finite element. */
502    /** @a Trans represents the mapping from the reference element of @a this
503        element into a subset of the reference space of the element @a fe, thus
504        allowing the "coarse" FiniteElement to be different from the "fine"
505        FiniteElement as when h-refinement is combined with p-refinement or
506        p-derefinement. It is assumed that both finite elements use the same
507        FiniteElement::MapType. */
508    virtual void GetTransferMatrix(const FiniteElement &fe,
509                                   ElementTransformation &Trans,
510                                   DenseMatrix &I) const;
511 
512    /** @brief Given a coefficient and a transformation, compute its projection
513        (approximation) in the local finite dimensional space in terms
514        of the degrees of freedom. */
515    /** The approximation used to project is usually local interpolation of
516        degrees of freedom. The derived class could use other methods not
517        implemented yet, e.g. local L2 projection. */
518    virtual void Project(Coefficient &coeff,
519                         ElementTransformation &Trans, Vector &dofs) const;
520 
521    /** @brief Given a vector coefficient and a transformation, compute its
522        projection (approximation) in the local finite dimensional space
523        in terms of the degrees of freedom. (VectorFiniteElements) */
524    /** The approximation used to project is usually local interpolation of
525        degrees of freedom. The derived class could use other methods not
526        implemented yet, e.g. local L2 projection. */
527    virtual void Project(VectorCoefficient &vc,
528                         ElementTransformation &Trans, Vector &dofs) const;
529 
530    /** @brief Given a vector of values at the finite element nodes and a
531        transformation, compute its projection (approximation) in the local
532        finite dimensional space in terms of the degrees of freedom. Valid for
533        VectorFiniteElements. */
534    virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
535                                  Vector &dofs) const;
536 
537    /** @brief Given a matrix coefficient and a transformation, compute an
538        approximation ("projection") in the local finite dimensional space in
539        terms of the degrees of freedom. For VectorFiniteElements, the rows of
540        the coefficient are projected in the vector space. */
541    virtual void ProjectMatrixCoefficient(
542       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
543 
544    /** @brief Project a delta function centered on the given @a vertex in
545        the local finite dimensional space represented by the @a dofs. */
546    virtual void ProjectDelta(int vertex, Vector &dofs) const;
547 
548    /** @brief Compute the embedding/projection matrix from the given
549        FiniteElement onto 'this' FiniteElement. The ElementTransformation is
550        included to support cases when the projection depends on it. */
551    virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
552                         DenseMatrix &I) const;
553 
554    /** @brief Compute the discrete gradient matrix from the given FiniteElement
555        onto 'this' FiniteElement. The ElementTransformation is included to
556        support cases when the matrix depends on it. */
557    virtual void ProjectGrad(const FiniteElement &fe,
558                             ElementTransformation &Trans,
559                             DenseMatrix &grad) const;
560 
561    /** @brief Compute the discrete curl matrix from the given FiniteElement onto
562        'this' FiniteElement. The ElementTransformation is included to support
563        cases when the matrix depends on it. */
564    virtual void ProjectCurl(const FiniteElement &fe,
565                             ElementTransformation &Trans,
566                             DenseMatrix &curl) const;
567 
568    /** @brief Compute the discrete divergence matrix from the given
569        FiniteElement onto 'this' FiniteElement. The ElementTransformation is
570        included to support cases when the matrix depends on it. */
571    virtual void ProjectDiv(const FiniteElement &fe,
572                            ElementTransformation &Trans,
573                            DenseMatrix &div) const;
574 
575    /** @brief Return a DofToQuad structure corresponding to the given
576        IntegrationRule using the given DofToQuad::Mode. */
577    /** See the documentation for DofToQuad for more details. */
578    virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
579                                          DofToQuad::Mode mode) const;
580    /// Deconstruct the FiniteElement
581    virtual ~FiniteElement();
582 
583    /** @brief Return true if the BasisType of @a b_type is closed
584        (has Quadrature1D points on the boundary). */
IsClosedType(int b_type)585    static bool IsClosedType(int b_type)
586    {
587       const int q_type = BasisType::GetQuadrature1D(b_type);
588       return ((q_type != Quadrature1D::Invalid) &&
589               (Quadrature1D::CheckClosed(q_type) != Quadrature1D::Invalid));
590    }
591 
592    /** @brief Return true if the BasisType of @a b_type is open
593        (doesn't have Quadrature1D points on the boundary). */
IsOpenType(int b_type)594    static bool IsOpenType(int b_type)
595    {
596       const int q_type = BasisType::GetQuadrature1D(b_type);
597       return ((q_type != Quadrature1D::Invalid) &&
598               (Quadrature1D::CheckOpen(q_type) != Quadrature1D::Invalid));
599    }
600 
601    /** @brief Ensure that the BasisType of @a b_type is closed
602        (has Quadrature1D points on the boundary). */
VerifyClosed(int b_type)603    static int VerifyClosed(int b_type)
604    {
605       MFEM_VERIFY(IsClosedType(b_type),
606                   "invalid closed basis type: " << b_type);
607       return b_type;
608    }
609 
610    /** @brief Ensure that the BasisType of @a b_type is open
611        (doesn't have Quadrature1D points on the boundary). */
VerifyOpen(int b_type)612    static int VerifyOpen(int b_type)
613    {
614       MFEM_VERIFY(IsOpenType(b_type), "invalid open basis type: " << b_type);
615       return b_type;
616    }
617 
618    /** @brief Ensure that the BasisType of @a b_type nodal
619        (satisfies the interpolation property). */
VerifyNodal(int b_type)620    static int VerifyNodal(int b_type)
621    {
622       return BasisType::CheckNodal(b_type);
623    }
624 };
625 
626 
627 /** @brief Class for finite elements with basis functions
628     that return scalar values. */
629 class ScalarFiniteElement : public FiniteElement
630 {
631 protected:
632 #ifndef MFEM_THREAD_SAFE
633    mutable Vector c_shape;
634 #endif
635 
CheckScalarFE(const FiniteElement & fe)636    static const ScalarFiniteElement &CheckScalarFE(const FiniteElement &fe)
637    {
638       MFEM_VERIFY(fe.GetRangeType() == SCALAR,
639                   "'fe' must be a ScalarFiniteElement");
640       return static_cast<const ScalarFiniteElement &>(fe);
641    }
642 
643    const DofToQuad &GetTensorDofToQuad(const class TensorBasisElement &tb,
644                                        const IntegrationRule &ir,
645                                        DofToQuad::Mode mode) const;
646 
647 public:
648    /** @brief Construct ScalarFiniteElement with given
649        @param D    Reference space dimension
650        @param G    Geometry type (of type Geometry::Type)
651        @param Do   Number of degrees of freedom in the FiniteElement
652        @param O    Order/degree of the FiniteElement
653        @param F    FunctionSpace type of the FiniteElement
654     */
ScalarFiniteElement(int D,Geometry::Type G,int Do,int O,int F=FunctionSpace::Pk)655    ScalarFiniteElement(int D, Geometry::Type G, int Do, int O,
656                        int F = FunctionSpace::Pk)
657 #ifdef MFEM_THREAD_SAFE
658       : FiniteElement(D, G, Do, O, F)
659    { deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; }
660 #else
661       : FiniteElement(D, G, Do, O, F), c_shape(dof)
662    { deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; }
663 #endif
664 
665    /** @brief Set the FiniteElement::MapType of the element to either VALUE or
666        INTEGRAL. Also sets the FiniteElement::DerivType to GRAD if the
667        FiniteElement::MapType is VALUE. */
SetMapType(int M)668    void SetMapType(int M)
669    {
670       MFEM_VERIFY(M == VALUE || M == INTEGRAL, "unknown MapType");
671       map_type = M;
672       deriv_type = (M == VALUE) ? GRAD : NONE;
673    }
674 
675 
676    /** @brief Get the matrix @a I that defines nodal interpolation
677        @a between this element and the refined element @a fine_fe. */
678    void NodalLocalInterpolation(ElementTransformation &Trans,
679                                 DenseMatrix &I,
680                                 const ScalarFiniteElement &fine_fe) const;
681 
682    /** @brief Get matrix @a I "Interpolation" defined through local
683        L2-projection in the space defined by the @a fine_fe. */
684    /** If the "fine" elements cannot represent all basis functions of the
685        "coarse" element, then boundary values from different sub-elements are
686        generally different. */
687    void ScalarLocalInterpolation(ElementTransformation &Trans,
688                                  DenseMatrix &I,
689                                  const ScalarFiniteElement &fine_fe) const;
690 
691    /** @brief Get restriction matrix @a R defined through local L2-projection
692         in the space defined by the @a coarse_fe. */
693    /** If the "fine" elements cannot represent all basis functions of the
694        "coarse" element, then boundary values from different sub-elements are
695        generally different. */
696    void ScalarLocalRestriction(ElementTransformation &Trans,
697                                DenseMatrix &R,
698                                const ScalarFiniteElement &coarse_fe) const;
699 
700    virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
701                                          DofToQuad::Mode mode) const;
702 };
703 
704 
705 /// Class for standard nodal finite elements.
706 class NodalFiniteElement : public ScalarFiniteElement
707 {
708 protected:
709    Array<int> lex_ordering;
710    void ProjectCurl_2D(const FiniteElement &fe,
711                        ElementTransformation &Trans,
712                        DenseMatrix &curl) const;
713 
714 public:
715    /** @brief Construct NodalFiniteElement with given
716        @param D    Reference space dimension
717        @param G    Geometry type (of type Geometry::Type)
718        @param Do   Number of degrees of freedom in the FiniteElement
719        @param O    Order/degree of the FiniteElement
720        @param F    FunctionSpace type of the FiniteElement
721    */
NodalFiniteElement(int D,Geometry::Type G,int Do,int O,int F=FunctionSpace::Pk)722    NodalFiniteElement(int D, Geometry::Type G, int Do, int O,
723                       int F = FunctionSpace::Pk)
724       : ScalarFiniteElement(D, G, Do, O, F) { }
725 
GetLocalInterpolation(ElementTransformation & Trans,DenseMatrix & I) const726    virtual void GetLocalInterpolation(ElementTransformation &Trans,
727                                       DenseMatrix &I) const
728    { NodalLocalInterpolation(Trans, I, *this); }
729 
730    virtual void GetLocalRestriction(ElementTransformation &Trans,
731                                     DenseMatrix &R) const;
732 
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const733    virtual void GetTransferMatrix(const FiniteElement &fe,
734                                   ElementTransformation &Trans,
735                                   DenseMatrix &I) const
736    { CheckScalarFE(fe).NodalLocalInterpolation(Trans, I, *this); }
737 
738    virtual void Project (Coefficient &coeff,
739                          ElementTransformation &Trans, Vector &dofs) const;
740 
741    virtual void Project (VectorCoefficient &vc,
742                          ElementTransformation &Trans, Vector &dofs) const;
743 
744    // (mc.height x mc.width) @ DOFs -> (Dof x mc.width x mc.height) in dofs
745    virtual void ProjectMatrixCoefficient(
746       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
747 
748    virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
749                         DenseMatrix &I) const;
750 
751    virtual void ProjectGrad(const FiniteElement &fe,
752                             ElementTransformation &Trans,
753                             DenseMatrix &grad) const;
754 
755    virtual void ProjectDiv(const FiniteElement &fe,
756                            ElementTransformation &Trans,
757                            DenseMatrix &div) const;
758 
759    /** @brief Get an Array<int> that maps lexicographically ordered indices to
760        the indices of the respective nodes/dofs/basis functions. Lexicographic
761        ordering of nodes is defined in terms of reference-space coordinates
762        (x,y,z). Lexicographically ordered nodes are listed first in order of
763        increasing x-coordinate, and then in order of increasing y-coordinate,
764        and finally in order of increasing z-coordinate.
765 
766        For example, the six nodes of a quadratic triangle are lexicographically
767        ordered as follows:
768 
769        5
770        |\
771        3 4
772        |  \
773        0-1-2
774 
775        The resulting array may be empty if the DOFs are already ordered
776        lexicographically, or if the finite element does not support creating
777        this permutation. The array returned is the same as the array given by
778        TensorBasisElement::GetDofMap, but it is also available for non-tensor
779        elements. */
GetLexicographicOrdering() const780    const Array<int> &GetLexicographicOrdering() const { return lex_ordering; }
781 };
782 
783 /** @brief Class for finite elements utilizing the
784     always positive Bernstein basis. */
785 class PositiveFiniteElement : public ScalarFiniteElement
786 {
787 public:
788    /** @brief Construct PositiveFiniteElement with given
789        @param D    Reference space dimension
790        @param G    Geometry type (of type Geometry::Type)
791        @param Do   Number of degrees of freedom in the FiniteElement
792        @param O    Order/degree of the FiniteElement
793        @param F    FunctionSpace type of the FiniteElement
794    */
PositiveFiniteElement(int D,Geometry::Type G,int Do,int O,int F=FunctionSpace::Pk)795    PositiveFiniteElement(int D, Geometry::Type G, int Do, int O,
796                          int F = FunctionSpace::Pk) :
797       ScalarFiniteElement(D, G, Do, O, F)
798    { }
799 
GetLocalInterpolation(ElementTransformation & Trans,DenseMatrix & I) const800    virtual void GetLocalInterpolation(ElementTransformation &Trans,
801                                       DenseMatrix &I) const
802    { ScalarLocalInterpolation(Trans, I, *this); }
803 
GetLocalRestriction(ElementTransformation & Trans,DenseMatrix & R) const804    virtual void GetLocalRestriction(ElementTransformation &Trans,
805                                     DenseMatrix &R) const
806    { ScalarLocalRestriction(Trans, R, *this); }
807 
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const808    virtual void GetTransferMatrix(const FiniteElement &fe,
809                                   ElementTransformation &Trans,
810                                   DenseMatrix &I) const
811    { CheckScalarFE(fe).ScalarLocalInterpolation(Trans, I, *this); }
812 
813    using FiniteElement::Project;
814 
815    // Low-order monotone "projection" (actually it is not a projection): the
816    // dofs are set to be the Coefficient values at the nodes.
817    virtual void Project(Coefficient &coeff,
818                         ElementTransformation &Trans, Vector &dofs) const;
819 
820    virtual void Project (VectorCoefficient &vc,
821                          ElementTransformation &Trans, Vector &dofs) const;
822 
823    virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
824                         DenseMatrix &I) const;
825 };
826 
827 /** @brief Intermediate class for finite elements whose basis functions return
828     vector values. */
829 class VectorFiniteElement : public FiniteElement
830 {
831    // Hide the scalar functions CalcShape and CalcDShape.
832 private:
833    /// Overrides the scalar CalcShape function to print an error.
834    virtual void CalcShape(const IntegrationPoint &ip,
835                           Vector &shape) const;
836 
837    /// Overrides the scalar CalcDShape function to print an error.
838    virtual void CalcDShape(const IntegrationPoint &ip,
839                            DenseMatrix &dshape) const;
840 
841 protected:
842    bool is_nodal;
843 #ifndef MFEM_THREAD_SAFE
844    mutable DenseMatrix J, Jinv;
845    mutable DenseMatrix curlshape, curlshape_J;
846 #endif
847    void SetDerivMembers();
848 
849    void CalcVShape_RT(ElementTransformation &Trans,
850                       DenseMatrix &shape) const;
851 
852    void CalcVShape_ND(ElementTransformation &Trans,
853                       DenseMatrix &shape) const;
854 
855    /** @brief Project a vector coefficient onto the RT basis functions
856        @param nk    Face normal vectors for this element type
857        @param d2n   Offset into nk for each degree of freedom
858        @param vc    Vector coefficient to be projected
859        @param Trans Transformation from reference to physical coordinates
860        @param dofs  Expansion coefficients for the approximation of vc
861    */
862    void Project_RT(const double *nk, const Array<int> &d2n,
863                    VectorCoefficient &vc, ElementTransformation &Trans,
864                    Vector &dofs) const;
865 
866    /// Projects the vector of values given at FE nodes to RT space
867    /** Project vector values onto the RT basis functions
868        @param nk    Face normal vectors for this element type
869        @param d2n   Offset into nk for each degree of freedom
870        @param vc    Vector values at each interpolation point
871        @param Trans Transformation from reference to physical coordinates
872        @param dofs  Expansion coefficients for the approximation of vc
873    */
874    void Project_RT(const double *nk, const Array<int> &d2n,
875                    Vector &vc, ElementTransformation &Trans,
876                    Vector &dofs) const;
877 
878    /// Project the rows of the matrix coefficient in an RT space
879    void ProjectMatrixCoefficient_RT(
880       const double *nk, const Array<int> &d2n,
881       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
882 
883    /** @brief Project vector-valued basis functions onto the RT basis functions
884        @param nk    Face normal vectors for this element type
885        @param d2n   Offset into nk for each degree of freedom
886        @param fe    Vector-valued finite element basis
887        @param Trans Transformation from reference to physical coordinates
888        @param I     Expansion coefficients for the approximation of each basis
889                     function
890 
891        Note: If the FiniteElement, fe, is scalar-valued the projection will
892              assume that a FiniteElementSpace is being used to define a vector
893              field using the scalar basis functions for each component of the
894              vector field.
895    */
896    void Project_RT(const double *nk, const Array<int> &d2n,
897                    const FiniteElement &fe, ElementTransformation &Trans,
898                    DenseMatrix &I) const;
899 
900    // rotated gradient in 2D
901    void ProjectGrad_RT(const double *nk, const Array<int> &d2n,
902                        const FiniteElement &fe, ElementTransformation &Trans,
903                        DenseMatrix &grad) const;
904 
905    // Compute the curl as a discrete operator from ND FE (fe) to ND FE (this).
906    // The natural FE for the range is RT, so this is an approximation.
907    void ProjectCurl_ND(const double *tk, const Array<int> &d2t,
908                        const FiniteElement &fe, ElementTransformation &Trans,
909                        DenseMatrix &curl) const;
910 
911    void ProjectCurl_RT(const double *nk, const Array<int> &d2n,
912                        const FiniteElement &fe, ElementTransformation &Trans,
913                        DenseMatrix &curl) const;
914 
915    /** @brief Project a vector coefficient onto the ND basis functions
916        @param tk    Edge tangent vectors for this element type
917        @param d2t   Offset into tk for each degree of freedom
918        @param vc    Vector coefficient to be projected
919        @param Trans Transformation from reference to physical coordinates
920        @param dofs  Expansion coefficients for the approximation of vc
921    */
922    void Project_ND(const double *tk, const Array<int> &d2t,
923                    VectorCoefficient &vc, ElementTransformation &Trans,
924                    Vector &dofs) const;
925 
926    /// Projects the vector of values given at FE nodes to ND space
927    /** Project vector values onto the ND basis functions
928        @param tk    Edge tangent vectors for this element type
929        @param d2t   Offset into tk for each degree of freedom
930        @param vc    Vector values at each interpolation point
931        @param Trans Transformation from reference to physical coordinates
932        @param dofs  Expansion coefficients for the approximation of vc
933    */
934    void Project_ND(const double *tk, const Array<int> &d2t,
935                    Vector &vc, ElementTransformation &Trans,
936                    Vector &dofs) const;
937 
938    /// Project the rows of the matrix coefficient in an ND space
939    void ProjectMatrixCoefficient_ND(
940       const double *tk, const Array<int> &d2t,
941       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
942 
943    /** @brief Project vector-valued basis functions onto the ND basis functions
944        @param tk    Edge tangent vectors for this element type
945        @param d2t   Offset into tk for each degree of freedom
946        @param fe    Vector-valued finite element basis
947        @param Trans Transformation from reference to physical coordinates
948        @param I     Expansion coefficients for the approximation of each basis
949                     function
950 
951        Note: If the FiniteElement, fe, is scalar-valued the projection will
952              assume that a FiniteElementSpace is being used to define a vector
953              field using the scalar basis functions for each component of the
954              vector field.
955    */
956    void Project_ND(const double *tk, const Array<int> &d2t,
957                    const FiniteElement &fe, ElementTransformation &Trans,
958                    DenseMatrix &I) const;
959 
960    void ProjectGrad_ND(const double *tk, const Array<int> &d2t,
961                        const FiniteElement &fe, ElementTransformation &Trans,
962                        DenseMatrix &grad) const;
963 
964    void LocalL2Projection_RT(const VectorFiniteElement &cfe,
965                              ElementTransformation &Trans,
966                              DenseMatrix &I) const;
967 
968    void LocalInterpolation_RT(const VectorFiniteElement &cfe,
969                               const double *nk, const Array<int> &d2n,
970                               ElementTransformation &Trans,
971                               DenseMatrix &I) const;
972 
973    void LocalL2Projection_ND(const VectorFiniteElement &cfe,
974                              ElementTransformation &Trans,
975                              DenseMatrix &I) const;
976 
977    void LocalInterpolation_ND(const VectorFiniteElement &cfe,
978                               const double *tk, const Array<int> &d2t,
979                               ElementTransformation &Trans,
980                               DenseMatrix &I) const;
981 
982    void LocalRestriction_RT(const double *nk, const Array<int> &d2n,
983                             ElementTransformation &Trans,
984                             DenseMatrix &R) const;
985 
986    void LocalRestriction_ND(const double *tk, const Array<int> &d2t,
987                             ElementTransformation &Trans,
988                             DenseMatrix &R) const;
989 
CheckVectorFE(const FiniteElement & fe)990    static const VectorFiniteElement &CheckVectorFE(const FiniteElement &fe)
991    {
992       if (fe.GetRangeType() != VECTOR)
993       { mfem_error("'fe' must be a VectorFiniteElement"); }
994       return static_cast<const VectorFiniteElement &>(fe);
995    }
996 
997 public:
VectorFiniteElement(int D,Geometry::Type G,int Do,int O,int M,int F=FunctionSpace::Pk)998    VectorFiniteElement (int D, Geometry::Type G, int Do, int O, int M,
999                         int F = FunctionSpace::Pk) :
1000 #ifdef MFEM_THREAD_SAFE
1001       FiniteElement(D, G, Do, O, F)
1002    { range_type = VECTOR; map_type = M; SetDerivMembers(); is_nodal = true; }
1003 #else
1004       FiniteElement(D, G, Do, O, F), Jinv(D)
1005    { range_type = VECTOR; map_type = M; SetDerivMembers(); is_nodal = true; }
1006 #endif
1007 };
1008 
1009 /// A 0D point finite element
1010 class PointFiniteElement : public NodalFiniteElement
1011 {
1012 public:
1013    /// Construct the PointFiniteElement
1014    PointFiniteElement();
1015 
1016    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1017 
1018    virtual void CalcDShape(const IntegrationPoint &ip,
1019                            DenseMatrix &dshape) const;
1020 };
1021 
1022 /// A 1D linear element with nodes on the endpoints
1023 class Linear1DFiniteElement : public NodalFiniteElement
1024 {
1025 public:
1026    /// Construct the Linear1DFiniteElement
1027    Linear1DFiniteElement();
1028 
1029    /** virtual function which evaluates the values of all
1030        shape functions at a given point ip and stores
1031        them in the vector shape of dimension Dof (2) */
1032    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1033 
1034    /** virtual function which evaluates the derivatives of all
1035        shape functions at a given point ip and stores them in
1036        the matrix dshape (Dof x Dim) (2 x 1) so that each row
1037        contains the derivative of one shape function */
1038    virtual void CalcDShape(const IntegrationPoint &ip,
1039                            DenseMatrix &dshape) const;
1040 };
1041 
1042 /// A 2D linear element on triangle with nodes at the vertices of the triangle
1043 class Linear2DFiniteElement : public NodalFiniteElement
1044 {
1045 public:
1046    /// Construct the Linear2DFiniteElement
1047    Linear2DFiniteElement();
1048 
1049    /** virtual function which evaluates the values of all
1050        shape functions at a given point ip and stores
1051        them in the vector shape of dimension Dof (3) */
1052    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1053 
1054    /** virtual function which evaluates the values of all
1055        partial derivatives of all shape functions at a given
1056        point ip and stores them in the matrix dshape (Dof x Dim) (3 x 2)
1057        so that each row contains the derivatives of one shape function */
1058    virtual void CalcDShape(const IntegrationPoint &ip,
1059                            DenseMatrix &dshape) const;
ProjectDelta(int vertex,Vector & dofs) const1060    virtual void ProjectDelta(int vertex, Vector &dofs) const
1061    { dofs = 0.0; dofs(vertex) = 1.0; }
1062 };
1063 
1064 /// A 2D bi-linear element on a square with nodes at the vertices of the square
1065 class BiLinear2DFiniteElement : public NodalFiniteElement
1066 {
1067 public:
1068    /// Construct the BiLinear2DFiniteElement
1069    BiLinear2DFiniteElement();
1070 
1071    /** virtual function which evaluates the values of all
1072        shape functions at a given point ip and stores
1073        them in the vector shape of dimension Dof (4) */
1074    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1075 
1076    /** virtual function which evaluates the values of all
1077        partial derivatives of all shape functions at a given
1078        point ip and stores them in the matrix dshape (Dof x Dim) (4 x 2)
1079        so that each row contains the derivatives of one shape function */
1080    virtual void CalcDShape(const IntegrationPoint &ip,
1081                            DenseMatrix &dshape) const;
1082    virtual void CalcHessian (const IntegrationPoint &ip,
1083                              DenseMatrix &h) const;
ProjectDelta(int vertex,Vector & dofs) const1084    virtual void ProjectDelta(int vertex, Vector &dofs) const
1085    { dofs = 0.0; dofs(vertex) = 1.0; } // { dofs = 1.0; }
1086 };
1087 
1088 /// A linear element on a triangle with nodes at the 3 "Gaussian" points
1089 class GaussLinear2DFiniteElement : public NodalFiniteElement
1090 {
1091 public:
1092    /// Construct the GaussLinear2DFiniteElement
1093    GaussLinear2DFiniteElement();
1094    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1095    virtual void CalcDShape(const IntegrationPoint &ip,
1096                            DenseMatrix &dshape) const;
1097    virtual void ProjectDelta(int vertex, Vector &dofs) const;
1098 };
1099 
1100 /// A 2D bi-linear element on a square with nodes at the "Gaussian" points
1101 class GaussBiLinear2DFiniteElement : public NodalFiniteElement
1102 {
1103 private:
1104    static const double p[2];
1105 
1106 public:
1107    /// Construct the FiniteElement
1108    GaussBiLinear2DFiniteElement();
1109    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1110    virtual void CalcDShape(const IntegrationPoint &ip,
1111                            DenseMatrix &dshape) const;
1112    virtual void ProjectDelta(int vertex, Vector &dofs) const;
1113 };
1114 
1115 /** @brief A 2D linear element on a square with 3 nodes at the
1116     vertices of the lower left triangle */
1117 class P1OnQuadFiniteElement : public NodalFiniteElement
1118 {
1119 public:
1120    /// Construct the P1OnQuadFiniteElement
1121    P1OnQuadFiniteElement();
1122    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1123    virtual void CalcDShape(const IntegrationPoint &ip,
1124                            DenseMatrix &dshape) const;
ProjectDelta(int vertex,Vector & dofs) const1125    virtual void ProjectDelta(int vertex, Vector &dofs) const
1126    { dofs = 1.0; }
1127 };
1128 
1129 /// A 1D quadratic finite element with uniformly spaced nodes
1130 class Quad1DFiniteElement : public NodalFiniteElement
1131 {
1132 public:
1133    /// Construct the Quad1DFiniteElement
1134    Quad1DFiniteElement();
1135 
1136    /** virtual function which evaluates the values of all
1137        shape functions at a given point ip and stores
1138        them in the vector shape of dimension Dof (3) */
1139    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1140 
1141    /** virtual function which evaluates the derivatives of all
1142        shape functions at a given point ip and stores them in
1143        the matrix dshape (Dof x Dim) (3 x 1) so that each row
1144        contains the derivative of one shape function */
1145    virtual void CalcDShape(const IntegrationPoint &ip,
1146                            DenseMatrix &dshape) const;
1147 };
1148 
1149 /// A 1D quadratic positive element utilizing the 2nd order Bernstein basis
1150 class QuadPos1DFiniteElement : public PositiveFiniteElement
1151 {
1152 public:
1153    /// Construct the QuadPos1DFiniteElement
1154    QuadPos1DFiniteElement();
1155    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1156    virtual void CalcDShape(const IntegrationPoint &ip,
1157                            DenseMatrix &dshape) const;
1158 };
1159 
1160 /** @brief A 2D quadratic element on triangle with nodes at the
1161     vertices and midpoints of the triangle. */
1162 class Quad2DFiniteElement : public NodalFiniteElement
1163 {
1164 public:
1165    /// Construct the Quad2DFiniteElement
1166    Quad2DFiniteElement();
1167 
1168    /** virtual function which evaluates the values of all
1169        shape functions at a given point ip and stores
1170        them in the vector shape of dimension Dof (6) */
1171    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1172 
1173    /** virtual function which evaluates the values of all
1174        partial derivatives of all shape functions at a given
1175        point ip and stores them in the matrix dshape (Dof x Dim) (6 x 2)
1176        so that each row contains the derivatives of one shape function */
1177    virtual void CalcDShape(const IntegrationPoint &ip,
1178                            DenseMatrix &dshape) const;
1179 
1180    virtual void CalcHessian (const IntegrationPoint &ip,
1181                              DenseMatrix &h) const;
1182    virtual void ProjectDelta(int vertex, Vector &dofs) const;
1183 };
1184 
1185 /// A quadratic element on triangle with nodes at the "Gaussian" points
1186 class GaussQuad2DFiniteElement : public NodalFiniteElement
1187 {
1188 private:
1189    static const double p[2];
1190    DenseMatrix A;
1191    mutable DenseMatrix D;
1192    mutable Vector pol;
1193 public:
1194    /// Construct the GaussQuad2DFiniteElement
1195    GaussQuad2DFiniteElement();
1196    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1197    virtual void CalcDShape(const IntegrationPoint &ip,
1198                            DenseMatrix &dshape) const;
1199    // virtual void ProjectDelta(int vertex, Vector &dofs) const;
1200 };
1201 
1202 /// A 2D bi-quadratic element on a square with uniformly spaced nodes
1203 class BiQuad2DFiniteElement : public NodalFiniteElement
1204 {
1205 public:
1206    /// Construct the BiQuad2DFiniteElement
1207    BiQuad2DFiniteElement();
1208 
1209    /** virtual function which evaluates the values of all
1210        shape functions at a given point ip and stores
1211        them in the vector shape of dimension Dof (9) */
1212    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1213 
1214    /** virtual function which evaluates the values of all
1215        partial derivatives of all shape functions at a given
1216        point ip and stores them in the matrix dshape (Dof x Dim) (9 x 2)
1217        so that each row contains the derivatives of one shape function */
1218    virtual void CalcDShape(const IntegrationPoint &ip,
1219                            DenseMatrix &dshape) const;
1220    virtual void ProjectDelta(int vertex, Vector &dofs) const;
1221 };
1222 
1223 
1224 /// A 2D positive bi-quadratic element on a square utilizing the 2nd order
1225 /// Bernstein basis
1226 class BiQuadPos2DFiniteElement : public PositiveFiniteElement
1227 {
1228 public:
1229    /// Construct the BiQuadPos2DFiniteElement
1230    BiQuadPos2DFiniteElement();
1231    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1232    virtual void CalcDShape(const IntegrationPoint &ip,
1233                            DenseMatrix &dshape) const;
1234    virtual void GetLocalInterpolation(ElementTransformation &Trans,
1235                                       DenseMatrix &I) const;
1236    using FiniteElement::Project;
1237    virtual void Project(Coefficient &coeff, ElementTransformation &Trans,
1238                         Vector &dofs) const;
1239    virtual void Project(VectorCoefficient &vc, ElementTransformation &Trans,
1240                         Vector &dofs) const;
ProjectDelta(int vertex,Vector & dofs) const1241    virtual void ProjectDelta(int vertex, Vector &dofs) const
1242    { dofs = 0.; dofs(vertex) = 1.; }
1243 };
1244 
1245 /// A 2D bi-quadratic element on a square with nodes at the 9 "Gaussian" points
1246 class GaussBiQuad2DFiniteElement : public NodalFiniteElement
1247 {
1248 public:
1249    /// Construct the GaussBiQuad2DFiniteElement
1250    GaussBiQuad2DFiniteElement();
1251    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1252    virtual void CalcDShape(const IntegrationPoint &ip,
1253                            DenseMatrix &dshape) const;
1254    // virtual void ProjectDelta(int vertex, Vector &dofs) const { dofs = 1.; }
1255 };
1256 
1257 
1258 /// A 2D bi-cubic element on a square with uniformly spaces nodes
1259 class BiCubic2DFiniteElement : public NodalFiniteElement
1260 {
1261 public:
1262    /// Construct the BiCubic2DFiniteElement
1263    BiCubic2DFiniteElement();
1264    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1265    virtual void CalcDShape(const IntegrationPoint &ip,
1266                            DenseMatrix &dshape) const;
1267 
1268    /// Compute the Hessian of second order partial derivatives at @a ip.
1269    virtual void CalcHessian (const IntegrationPoint &ip,
1270                              DenseMatrix &h) const;
1271 };
1272 
1273 /// A 1D cubic element with uniformly spaced nodes
1274 class Cubic1DFiniteElement : public NodalFiniteElement
1275 {
1276 public:
1277    /// Construct the Cubic1DFiniteElement
1278    Cubic1DFiniteElement();
1279 
1280    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1281 
1282    virtual void CalcDShape(const IntegrationPoint &ip,
1283                            DenseMatrix &dshape) const;
1284 };
1285 
1286 /// A 2D cubic element on a triangle with uniformly spaced nodes
1287 class Cubic2DFiniteElement : public NodalFiniteElement
1288 {
1289 public:
1290    /// Construct the Cubic2DFiniteElement
1291    Cubic2DFiniteElement();
1292 
1293    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1294 
1295    virtual void CalcDShape(const IntegrationPoint &ip,
1296                            DenseMatrix &dshape) const;
1297 
1298    virtual void CalcHessian (const IntegrationPoint &ip,
1299                              DenseMatrix &h) const;
1300 };
1301 
1302 /// A 3D cubic element on a tetrahedron with 20 nodes at the thirds of the
1303 /// tetrahedron
1304 class Cubic3DFiniteElement : public NodalFiniteElement
1305 {
1306 public:
1307    /// Construct the Cubic3DFiniteElement
1308    Cubic3DFiniteElement();
1309 
1310    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1311 
1312    virtual void CalcDShape(const IntegrationPoint &ip,
1313                            DenseMatrix &dshape) const;
1314 };
1315 
1316 /// A 2D constant element on a triangle
1317 class P0TriangleFiniteElement : public NodalFiniteElement
1318 {
1319 public:
1320    /// Construct the P0TriangleFiniteElement
1321    P0TriangleFiniteElement();
1322 
1323    /// evaluate shape function - constant 1
1324    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1325 
1326    /// evaluate derivatives of shape function - constant 0
1327    virtual void CalcDShape(const IntegrationPoint &ip,
1328                            DenseMatrix &dshape) const;
ProjectDelta(int vertex,Vector & dofs) const1329    virtual void ProjectDelta(int vertex, Vector &dofs) const
1330    { dofs(0) = 1.0; }
1331 };
1332 
1333 
1334 /// A 2D constant element on a square
1335 class P0QuadFiniteElement : public NodalFiniteElement
1336 {
1337 public:
1338    /// Construct the P0QuadFiniteElement
1339    P0QuadFiniteElement();
1340    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1341    virtual void CalcDShape(const IntegrationPoint &ip,
1342                            DenseMatrix &dshape) const;
ProjectDelta(int vertex,Vector & dofs) const1343    virtual void ProjectDelta(int vertex, Vector &dofs) const
1344    { dofs(0) = 1.0; }
1345 };
1346 
1347 
1348 /** @brief A 3D linear element on a tetrahedron with nodes at the
1349     vertices of the tetrahedron */
1350 class Linear3DFiniteElement : public NodalFiniteElement
1351 {
1352 public:
1353    /// Construct the Linear3DFiniteElement
1354    Linear3DFiniteElement();
1355 
1356    /** @brief virtual function which evaluates the values of all
1357        shape functions at a given point ip and stores
1358        them in the vector shape of dimension Dof (4) */
1359    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1360 
1361    /** @brief virtual function which evaluates the values of all
1362        partial derivatives of all shape functions at a given
1363        point ip and stores them in the matrix dshape (Dof x Dim) (4 x 3)
1364        so that each row contains the derivatives of one shape function */
1365    virtual void CalcDShape(const IntegrationPoint &ip,
1366                            DenseMatrix &dshape) const;
1367 
ProjectDelta(int vertex,Vector & dofs) const1368    virtual void ProjectDelta(int vertex, Vector &dofs) const
1369    { dofs = 0.0; dofs(vertex) = 1.0; }
1370 
1371    /** @brief Get the dofs associated with the given @a face.
1372        @a *dofs is set to an internal array of the local dofc on the
1373        face, while *ndofs is set to the number of dofs on that face.
1374    */
1375    virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
1376 };
1377 
1378 /// A 3D quadratic element on a tetrahedron with uniformly spaced nodes
1379 class Quadratic3DFiniteElement : public NodalFiniteElement
1380 {
1381 public:
1382    /// Construct the Quadratic3DFiniteElement
1383    Quadratic3DFiniteElement();
1384 
1385    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1386 
1387    virtual void CalcDShape(const IntegrationPoint &ip,
1388                            DenseMatrix &dshape) const;
1389 };
1390 
1391 /// A 3D tri-linear element on a cube with nodes at the vertices of the cube
1392 class TriLinear3DFiniteElement : public NodalFiniteElement
1393 {
1394 public:
1395    /// Construct the TriLinear3DFiniteElement
1396    TriLinear3DFiniteElement();
1397 
1398    /** virtual function which evaluates the values of all
1399        shape functions at a given point ip and stores
1400        them in the vector shape of dimension Dof (8) */
1401    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1402 
1403    /** virtual function which evaluates the values of all
1404        partial derivatives of all shape functions at a given
1405        point ip and stores them in the matrix dshape (Dof x Dim) (8 x 3)
1406        so that each row contains the derivatives of one shape function */
1407    virtual void CalcDShape(const IntegrationPoint &ip,
1408                            DenseMatrix &dshape) const;
1409 
ProjectDelta(int vertex,Vector & dofs) const1410    virtual void ProjectDelta(int vertex, Vector &dofs) const
1411    { dofs = 0.0; dofs(vertex) = 1.0; }
1412 };
1413 
1414 
1415 /// A 2D Crouzeix-Raviart element on triangle
1416 class CrouzeixRaviartFiniteElement : public NodalFiniteElement
1417 {
1418 public:
1419    /// Construct the CrouzeixRaviartFiniteElement
1420    CrouzeixRaviartFiniteElement();
1421    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1422    virtual void CalcDShape(const IntegrationPoint &ip,
1423                            DenseMatrix &dshape) const;
ProjectDelta(int vertex,Vector & dofs) const1424    virtual void ProjectDelta(int vertex, Vector &dofs) const
1425    { dofs = 1.0; }
1426 };
1427 
1428 /// A 2D Crouzeix-Raviart finite element on square
1429 class CrouzeixRaviartQuadFiniteElement : public NodalFiniteElement
1430 {
1431 public:
1432    /// Construct the CrouzeixRaviartQuadFiniteElement
1433    CrouzeixRaviartQuadFiniteElement();
1434    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1435    virtual void CalcDShape(const IntegrationPoint &ip,
1436                            DenseMatrix &dshape) const;
1437 };
1438 
1439 
1440 /// A 1D constant element on a segment
1441 class P0SegmentFiniteElement : public NodalFiniteElement
1442 {
1443 public:
1444    /// Construct the P0SegmentFiniteElement with dummy order @a Ord
1445    P0SegmentFiniteElement(int Ord = 0);
1446    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1447    virtual void CalcDShape(const IntegrationPoint &ip,
1448                            DenseMatrix &dshape) const;
1449 };
1450 
1451 /** @brief A 2D 1st order Raviart-Thomas vector element on a triangle */
1452 class RT0TriangleFiniteElement : public VectorFiniteElement
1453 {
1454 private:
1455    static const double nk[3][2];
1456 
1457 public:
1458    /// Construct the RT0TriangleFiniteElement
1459    RT0TriangleFiniteElement();
1460 
1461    virtual void CalcVShape(const IntegrationPoint &ip,
1462                            DenseMatrix &shape) const;
1463 
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const1464    virtual void CalcVShape(ElementTransformation &Trans,
1465                            DenseMatrix &shape) const
1466    { CalcVShape_RT(Trans, shape); }
1467 
1468    virtual void CalcDivShape(const IntegrationPoint &ip,
1469                              Vector &divshape) const;
1470 
1471    virtual void GetLocalInterpolation (ElementTransformation &Trans,
1472                                        DenseMatrix &I) const;
1473 
1474    using FiniteElement::Project;
1475 
1476    virtual void Project (VectorCoefficient &vc,
1477                          ElementTransformation &Trans, Vector &dofs) const;
1478 };
1479 
1480 /** @brief A 2D 1st order Raviart-Thomas vector element on a square*/
1481 class RT0QuadFiniteElement : public VectorFiniteElement
1482 {
1483 private:
1484    static const double nk[4][2];
1485 
1486 public:
1487    /// Construct the RT0QuadFiniteElement
1488    RT0QuadFiniteElement();
1489 
1490    virtual void CalcVShape(const IntegrationPoint &ip,
1491                            DenseMatrix &shape) const;
1492 
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const1493    virtual void CalcVShape(ElementTransformation &Trans,
1494                            DenseMatrix &shape) const
1495    { CalcVShape_RT(Trans, shape); }
1496 
1497    virtual void CalcDivShape(const IntegrationPoint &ip,
1498                              Vector &divshape) const;
1499 
1500    virtual void GetLocalInterpolation (ElementTransformation &Trans,
1501                                        DenseMatrix &I) const;
1502 
1503    using FiniteElement::Project;
1504 
1505    virtual void Project (VectorCoefficient &vc,
1506                          ElementTransformation &Trans, Vector &dofs) const;
1507 };
1508 
1509 /** @brief A 2D 2nd order Raviart-Thomas vector element on a triangle */
1510 class RT1TriangleFiniteElement : public VectorFiniteElement
1511 {
1512 private:
1513    static const double nk[8][2];
1514 
1515 public:
1516    /// Construct the RT1TriangleFiniteElement
1517    RT1TriangleFiniteElement();
1518 
1519    virtual void CalcVShape(const IntegrationPoint &ip,
1520                            DenseMatrix &shape) const;
1521 
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const1522    virtual void CalcVShape(ElementTransformation &Trans,
1523                            DenseMatrix &shape) const
1524    { CalcVShape_RT(Trans, shape); }
1525 
1526    virtual void CalcDivShape(const IntegrationPoint &ip,
1527                              Vector &divshape) const;
1528 
1529    virtual void GetLocalInterpolation (ElementTransformation &Trans,
1530                                        DenseMatrix &I) const;
1531 
1532    using FiniteElement::Project;
1533 
1534    virtual void Project (VectorCoefficient &vc,
1535                          ElementTransformation &Trans, Vector &dofs) const;
1536 };
1537 
1538 /** @brief A 2D 2nd order Raviart-Thomas vector element on a square */
1539 class RT1QuadFiniteElement : public VectorFiniteElement
1540 {
1541 private:
1542    static const double nk[12][2];
1543 
1544 public:
1545    /// Construct the RT1QuadFiniteElement
1546    RT1QuadFiniteElement();
1547 
1548    virtual void CalcVShape(const IntegrationPoint &ip,
1549                            DenseMatrix &shape) const;
1550 
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const1551    virtual void CalcVShape(ElementTransformation &Trans,
1552                            DenseMatrix &shape) const
1553    { CalcVShape_RT(Trans, shape); }
1554 
1555    virtual void CalcDivShape(const IntegrationPoint &ip,
1556                              Vector &divshape) const;
1557 
1558    virtual void GetLocalInterpolation (ElementTransformation &Trans,
1559                                        DenseMatrix &I) const;
1560 
1561    using FiniteElement::Project;
1562 
1563    virtual void Project (VectorCoefficient &vc,
1564                          ElementTransformation &Trans, Vector &dofs) const;
1565 };
1566 
1567 /** @brief A 2D 3rd order Raviart-Thomas vector element on a triangle */
1568 class RT2TriangleFiniteElement : public VectorFiniteElement
1569 {
1570 private:
1571    static const double M[15][15];
1572 public:
1573    /// Construct the RT2TriangleFiniteElement
1574    RT2TriangleFiniteElement();
1575 
1576    virtual void CalcVShape(const IntegrationPoint &ip,
1577                            DenseMatrix &shape) const;
1578 
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const1579    virtual void CalcVShape(ElementTransformation &Trans,
1580                            DenseMatrix &shape) const
1581    { CalcVShape_RT(Trans, shape); }
1582 
1583    virtual void CalcDivShape(const IntegrationPoint &ip,
1584                              Vector &divshape) const;
1585 };
1586 
1587 /** @brief A 2D 3rd order Raviart-Thomas vector element on a square */
1588 class RT2QuadFiniteElement : public VectorFiniteElement
1589 {
1590 private:
1591    static const double nk[24][2];
1592    static const double pt[4];
1593    static const double dpt[3];
1594 
1595 public:
1596    /// Construct the RT2QuadFiniteElement
1597    RT2QuadFiniteElement();
1598 
1599    virtual void CalcVShape(const IntegrationPoint &ip,
1600                            DenseMatrix &shape) const;
1601 
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const1602    virtual void CalcVShape(ElementTransformation &Trans,
1603                            DenseMatrix &shape) const
1604    { CalcVShape_RT(Trans, shape); }
1605 
1606    virtual void CalcDivShape(const IntegrationPoint &ip,
1607                              Vector &divshape) const;
1608 
1609    virtual void GetLocalInterpolation (ElementTransformation &Trans,
1610                                        DenseMatrix &I) const;
1611 
1612    using FiniteElement::Project;
1613 
1614    virtual void Project (VectorCoefficient &vc,
1615                          ElementTransformation &Trans, Vector &dofs) const;
1616 };
1617 
1618 /// A 1D linear element with nodes at 1/3 and 2/3 (trace of RT1)
1619 class P1SegmentFiniteElement : public NodalFiniteElement
1620 {
1621 public:
1622    /// Construct the P1SegmentFiniteElement
1623    P1SegmentFiniteElement();
1624    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1625    virtual void CalcDShape(const IntegrationPoint &ip,
1626                            DenseMatrix &dshape) const;
1627 };
1628 
1629 /// A 1D quadratic element with nodes at the Gaussian points (trace of RT2)
1630 class P2SegmentFiniteElement : public NodalFiniteElement
1631 {
1632 public:
1633    /// Construct the P2SegmentFiniteElement
1634    P2SegmentFiniteElement();
1635    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1636    virtual void CalcDShape(const IntegrationPoint &ip,
1637                            DenseMatrix &dshape) const;
1638 };
1639 
1640 /// A 1D element with uniform nodes
1641 class Lagrange1DFiniteElement : public NodalFiniteElement
1642 {
1643 private:
1644    Vector rwk;
1645 #ifndef MFEM_THREAD_SAFE
1646    mutable Vector rxxk;
1647 #endif
1648 public:
1649    /// Construct the Lagrange1DFiniteElement with the provided @a degree
1650    Lagrange1DFiniteElement (int degree);
1651    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1652    virtual void CalcDShape(const IntegrationPoint &ip,
1653                            DenseMatrix &dshape) const;
1654 };
1655 
1656 /// A 3D Crouzeix-Raviart element on the tetrahedron.
1657 class P1TetNonConfFiniteElement : public NodalFiniteElement
1658 {
1659 public:
1660    /// Construct the P1TetNonConfFiniteElement
1661    P1TetNonConfFiniteElement();
1662    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1663    virtual void CalcDShape(const IntegrationPoint &ip,
1664                            DenseMatrix &dshape) const;
1665 };
1666 
1667 /// A 3D constant element on a tetrahedron
1668 class P0TetFiniteElement : public NodalFiniteElement
1669 {
1670 public:
1671    /// Construct the P0TetFiniteElement
1672    P0TetFiniteElement ();
1673    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1674    virtual void CalcDShape(const IntegrationPoint &ip,
1675                            DenseMatrix &dshape) const;
ProjectDelta(int vertex,Vector & dofs) const1676    virtual void ProjectDelta(int vertex, Vector &dofs) const
1677    { dofs(0) = 1.0; }
1678 };
1679 
1680 /// A 3D constant element on a cube
1681 class P0HexFiniteElement : public NodalFiniteElement
1682 {
1683 public:
1684    /// Construct the P0HexFiniteElement
1685    P0HexFiniteElement ();
1686    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1687    virtual void CalcDShape(const IntegrationPoint &ip,
1688                            DenseMatrix &dshape) const;
ProjectDelta(int vertex,Vector & dofs) const1689    virtual void ProjectDelta(int vertex, Vector &dofs) const
1690    { dofs(0) = 1.0; }
1691 };
1692 
1693 /** @brief Tensor products of 1D Lagrange1DFiniteElement
1694     (only degree 2 is functional) */
1695 class LagrangeHexFiniteElement : public NodalFiniteElement
1696 {
1697 private:
1698    Lagrange1DFiniteElement * fe1d;
1699    int dof1d;
1700    int *I, *J, *K;
1701 #ifndef MFEM_THREAD_SAFE
1702    mutable Vector shape1dx, shape1dy, shape1dz;
1703    mutable DenseMatrix dshape1dx, dshape1dy, dshape1dz;
1704 #endif
1705 
1706 public:
1707    /// Construct the LagrangeHexFiniteElement with the provided @a degree
1708    LagrangeHexFiniteElement (int degree);
1709    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1710    virtual void CalcDShape(const IntegrationPoint &ip,
1711                            DenseMatrix &dshape) const;
1712    ~LagrangeHexFiniteElement ();
1713 };
1714 
1715 
1716 /// A 1D refined linear element
1717 class RefinedLinear1DFiniteElement : public NodalFiniteElement
1718 {
1719 public:
1720    /// Construct the RefinedLinear1DFiniteElement
1721    RefinedLinear1DFiniteElement();
1722 
1723    /** virtual function which evaluates the values of all
1724        shape functions at a given point ip and stores
1725        them in the vector shape of dimension Dof (3) */
1726    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1727 
1728    /** virtual function which evaluates the derivatives of all
1729        shape functions at a given point ip and stores them in
1730        the matrix dshape (Dof x Dim) (3 x 1) so that each row
1731        contains the derivative of one shape function */
1732    virtual void CalcDShape(const IntegrationPoint &ip,
1733                            DenseMatrix &dshape) const;
1734 };
1735 
1736 /// A 2D refined linear element on a triangle
1737 class RefinedLinear2DFiniteElement : public NodalFiniteElement
1738 {
1739 public:
1740    /// Construct the RefinedLinear2DFiniteElement
1741    RefinedLinear2DFiniteElement();
1742 
1743    /** virtual function which evaluates the values of all
1744        shape functions at a given point ip and stores
1745        them in the vector shape of dimension Dof (6) */
1746    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1747 
1748    /** virtual function which evaluates the values of all
1749        partial derivatives of all shape functions at a given
1750        point ip and stores them in the matrix dshape (Dof x Dim) (6 x 2)
1751        so that each row contains the derivatives of one shape function */
1752    virtual void CalcDShape(const IntegrationPoint &ip,
1753                            DenseMatrix &dshape) const;
1754 };
1755 
1756 /// A 2D refined linear element on a tetrahedron
1757 class RefinedLinear3DFiniteElement : public NodalFiniteElement
1758 {
1759 public:
1760    /// Construct the RefinedLinear3DFiniteElement
1761    RefinedLinear3DFiniteElement();
1762 
1763    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1764 
1765    virtual void CalcDShape(const IntegrationPoint &ip,
1766                            DenseMatrix &dshape) const;
1767 };
1768 
1769 /// A 2D refined bi-linear FE on a square
1770 class RefinedBiLinear2DFiniteElement : public NodalFiniteElement
1771 {
1772 public:
1773    /// Construct the RefinedBiLinear2DFiniteElement
1774    RefinedBiLinear2DFiniteElement();
1775 
1776    /** virtual function which evaluates the values of all
1777        shape functions at a given point ip and stores
1778        them in the vector shape of dimension Dof (9) */
1779    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1780 
1781    /** virtual function which evaluates the values of all
1782        partial derivatives of all shape functions at a given
1783        point ip and stores them in the matrix dshape (Dof x Dim) (9 x 2)
1784        so that each row contains the derivatives of one shape function */
1785    virtual void CalcDShape(const IntegrationPoint &ip,
1786                            DenseMatrix &dshape) const;
1787 };
1788 
1789 /// A 3D refined tri-linear element on a cube
1790 class RefinedTriLinear3DFiniteElement : public NodalFiniteElement
1791 {
1792 public:
1793    /// Construct the RefinedTriLinear3DFiniteElement
1794    RefinedTriLinear3DFiniteElement();
1795 
1796    /** virtual function which evaluates the values of all
1797        shape functions at a given point ip and stores
1798        them in the vector shape of dimension Dof (9) */
1799    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1800 
1801    /** virtual function which evaluates the values of all
1802        partial derivatives of all shape functions at a given
1803        point ip and stores them in the matrix dshape (Dof x Dim) (9 x 2)
1804        so that each row contains the derivatives of one shape function */
1805    virtual void CalcDShape(const IntegrationPoint &ip,
1806                            DenseMatrix &dshape) const;
1807 };
1808 
1809 
1810 /// A 3D 1st order Nedelec element on a cube
1811 class Nedelec1HexFiniteElement : public VectorFiniteElement
1812 {
1813 private:
1814    static const double tk[12][3];
1815 
1816 public:
1817    /// Construct the Nedelec1HexFiniteElement
1818    Nedelec1HexFiniteElement();
1819    virtual void CalcVShape(const IntegrationPoint &ip,
1820                            DenseMatrix &shape) const;
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const1821    virtual void CalcVShape(ElementTransformation &Trans,
1822                            DenseMatrix &shape) const
1823    { CalcVShape_ND(Trans, shape); }
1824    virtual void CalcCurlShape(const IntegrationPoint &ip,
1825                               DenseMatrix &curl_shape) const;
1826    virtual void GetLocalInterpolation (ElementTransformation &Trans,
1827                                        DenseMatrix &I) const;
1828    using FiniteElement::Project;
1829    virtual void Project (VectorCoefficient &vc,
1830                          ElementTransformation &Trans, Vector &dofs) const;
1831 };
1832 
1833 
1834 /// A 3D 1st order Nedelec element on a tetrahedron
1835 class Nedelec1TetFiniteElement : public VectorFiniteElement
1836 {
1837 private:
1838    static const double tk[6][3];
1839 
1840 public:
1841    /// Construct the Nedelec1TetFiniteElement
1842    Nedelec1TetFiniteElement();
1843    virtual void CalcVShape(const IntegrationPoint &ip,
1844                            DenseMatrix &shape) const;
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const1845    virtual void CalcVShape(ElementTransformation &Trans,
1846                            DenseMatrix &shape) const
1847    { CalcVShape_ND(Trans, shape); }
1848    virtual void CalcCurlShape(const IntegrationPoint &ip,
1849                               DenseMatrix &curl_shape) const;
1850    virtual void GetLocalInterpolation (ElementTransformation &Trans,
1851                                        DenseMatrix &I) const;
1852    using FiniteElement::Project;
1853    virtual void Project (VectorCoefficient &vc,
1854                          ElementTransformation &Trans, Vector &dofs) const;
1855 };
1856 
1857 
1858 /// A 3D 0th order Raviert-Thomas element on a cube
1859 class RT0HexFiniteElement : public VectorFiniteElement
1860 {
1861 private:
1862    static const double nk[6][3];
1863 
1864 public:
1865    /// Construct the RT0HexFiniteElement
1866    RT0HexFiniteElement();
1867 
1868    virtual void CalcVShape(const IntegrationPoint &ip,
1869                            DenseMatrix &shape) const;
1870 
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const1871    virtual void CalcVShape(ElementTransformation &Trans,
1872                            DenseMatrix &shape) const
1873    { CalcVShape_RT(Trans, shape); }
1874 
1875    virtual void CalcDivShape(const IntegrationPoint &ip,
1876                              Vector &divshape) const;
1877 
1878    virtual void GetLocalInterpolation (ElementTransformation &Trans,
1879                                        DenseMatrix &I) const;
1880 
1881    using FiniteElement::Project;
1882 
1883    virtual void Project (VectorCoefficient &vc,
1884                          ElementTransformation &Trans, Vector &dofs) const;
1885 };
1886 
1887 
1888 /// A 3D 1st order Raviert-Thomas element on a cube
1889 class RT1HexFiniteElement : public VectorFiniteElement
1890 {
1891 private:
1892    static const double nk[36][3];
1893 
1894 public:
1895    /// Construct the RT1HexFiniteElement
1896    RT1HexFiniteElement();
1897 
1898    virtual void CalcVShape(const IntegrationPoint &ip,
1899                            DenseMatrix &shape) const;
1900 
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const1901    virtual void CalcVShape(ElementTransformation &Trans,
1902                            DenseMatrix &shape) const
1903    { CalcVShape_RT(Trans, shape); }
1904 
1905    virtual void CalcDivShape(const IntegrationPoint &ip,
1906                              Vector &divshape) const;
1907 
1908    virtual void GetLocalInterpolation (ElementTransformation &Trans,
1909                                        DenseMatrix &I) const;
1910 
1911    using FiniteElement::Project;
1912 
1913    virtual void Project (VectorCoefficient &vc,
1914                          ElementTransformation &Trans, Vector &dofs) const;
1915 };
1916 
1917 
1918 /// A 3D 0th order Raviert-Thomas element on a tetrahedron
1919 class RT0TetFiniteElement : public VectorFiniteElement
1920 {
1921 private:
1922    static const double nk[4][3];
1923 
1924 public:
1925    /// Construct the RT0TetFiniteElement
1926    RT0TetFiniteElement();
1927 
1928    virtual void CalcVShape(const IntegrationPoint &ip,
1929                            DenseMatrix &shape) const;
1930 
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const1931    virtual void CalcVShape(ElementTransformation &Trans,
1932                            DenseMatrix &shape) const
1933    { CalcVShape_RT(Trans, shape); }
1934 
1935    virtual void CalcDivShape(const IntegrationPoint &ip,
1936                              Vector &divshape) const;
1937 
1938    virtual void GetLocalInterpolation (ElementTransformation &Trans,
1939                                        DenseMatrix &I) const;
1940 
1941    using FiniteElement::Project;
1942 
1943    virtual void Project (VectorCoefficient &vc,
1944                          ElementTransformation &Trans, Vector &dofs) const;
1945 };
1946 
1947 
1948 class RotTriLinearHexFiniteElement : public NodalFiniteElement
1949 {
1950 public:
1951    /// Construct the RotTriLinearHexFiniteElement
1952    RotTriLinearHexFiniteElement();
1953    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
1954    virtual void CalcDShape(const IntegrationPoint &ip,
1955                            DenseMatrix &dshape) const;
1956 };
1957 
1958 
1959 /// Class for computing 1D special polynomials and their associated basis
1960 /// functions
1961 class Poly_1D
1962 {
1963 public:
1964    enum EvalType
1965    {
1966       ChangeOfBasis = 0, // Use change of basis, O(p^2) Evals
1967       Barycentric   = 1, // Use barycentric Lagrangian interpolation, O(p) Evals
1968       Positive      = 2, // Fast evaluation of Bernstein polynomials
1969       Integrated    = 3, // Integrated indicator functions (cf. Gerritsma)
1970       NumEvalTypes  = 4  // Keep count of the number of eval types
1971    };
1972 
1973    class Basis
1974    {
1975    private:
1976       int etype;
1977       DenseMatrixInverse Ai;
1978       mutable Vector x, w;
1979       // The following data members are used for "integrated basis type", which
1980       // is defined in terms of nodal basis of one degree higher.
1981       mutable Vector u_aux, d_aux, d2_aux;
1982       Basis *auxiliary_basis; // Non-NULL only for etype == Integrated
1983 
1984    public:
1985       /// Create a nodal or positive (Bernstein) basis
1986       Basis(const int p, const double *nodes, EvalType etype = Barycentric);
1987       void Eval(const double x, Vector &u) const;
1988       void Eval(const double x, Vector &u, Vector &d) const;
1989       void Eval(const double x, Vector &u, Vector &d, Vector &d2) const;
1990       /// Evaluate the "integrated" basis, which is given by the negative
1991       /// partial sum of the corresponding closed basis derivatives. The closed
1992       /// basis derivatives are given by @a d, and the result is stored in @a i.
1993       void EvalIntegrated(const Vector &d, Vector &i) const;
IsIntegratedType() const1994       bool IsIntegratedType() const { return etype == Integrated; }
1995       ~Basis();
1996    };
1997 
1998 private:
1999    typedef std::map< int, Array<double*>* > PointsMap;
2000    typedef std::map< int, Array<Basis*>* > BasisMap;
2001 
2002    MemoryType h_mt;
2003    PointsMap points_container;
2004    BasisMap  bases_container;
2005 
2006    static Array2D<int> binom;
2007 
2008    static void CalcMono(const int p, const double x, double *u);
2009    static void CalcMono(const int p, const double x, double *u, double *d);
2010 
2011    static void CalcChebyshev(const int p, const double x, double *u);
2012    static void CalcChebyshev(const int p, const double x, double *u, double *d);
2013    static void CalcChebyshev(const int p, const double x, double *u, double *d,
2014                              double *dd);
2015 
2016    QuadratureFunctions1D quad_func;
2017 
2018 public:
Poly_1D()2019    Poly_1D(): h_mt(MemoryType::HOST) { }
2020 
2021    /** @brief Get a pointer to an array containing the binomial coefficients "p
2022        choose k" for k=0,...,p for the given p. */
2023    static const int *Binom(const int p);
2024 
2025    /** @brief Get the coordinates of the points of the given BasisType,
2026        @a btype.
2027 
2028        @param[in] p      The polynomial degree; the number of points is `p+1`.
2029        @param[in] btype  The BasisType.
2030 
2031        @return A pointer to an array containing the `p+1` coordinates of the
2032                points. Returns NULL if the BasisType has no associated set of
2033                points. */
2034    const double *GetPoints(const int p, const int btype);
2035 
2036    /// Get coordinates of an open (GaussLegendre) set of points if degree @a p
OpenPoints(const int p,const int btype=BasisType::GaussLegendre)2037    const double *OpenPoints(const int p,
2038                             const int btype = BasisType::GaussLegendre)
2039    { return GetPoints(p, btype); }
2040 
2041    /// Get coordinates of a closed (GaussLegendre) set of points if degree @a p
ClosedPoints(const int p,const int btype=BasisType::GaussLobatto)2042    const double *ClosedPoints(const int p,
2043                               const int btype = BasisType::GaussLobatto)
2044    { return GetPoints(p, btype); }
2045 
2046    /** @brief Get a Poly_1D::Basis object of the given degree and BasisType,
2047        @a btype.
2048 
2049        @param[in] p      The polynomial degree of the basis.
2050        @param[in] btype  The BasisType.
2051 
2052        @return A reference to an object of type Poly_1D::Basis that represents
2053                the requested basis type. */
2054    Basis &GetBasis(const int p, const int btype);
2055 
2056    /** @brief Evaluate the values of a hierarchical 1D basis at point x
2057        hierarchical = k-th basis function is degree k polynomial */
CalcBasis(const int p,const double x,double * u)2058    static void CalcBasis(const int p, const double x, double *u)
2059    // { CalcMono(p, x, u); }
2060    // Bernstein basis is not hierarchical --> does not work for triangles
2061    //  and tetrahedra
2062    // { CalcBernstein(p, x, u); }
2063    // { CalcLegendre(p, x, u); }
2064    { CalcChebyshev(p, x, u); }
2065 
2066    /// Evaluate the values and derivatives of a hierarchical 1D basis at point @a x
CalcBasis(const int p,const double x,double * u,double * d)2067    static void CalcBasis(const int p, const double x, double *u, double *d)
2068    // { CalcMono(p, x, u, d); }
2069    // { CalcBernstein(p, x, u, d); }
2070    // { CalcLegendre(p, x, u, d); }
2071    { CalcChebyshev(p, x, u, d); }
2072 
2073    /// Evaluate the values, derivatives and second derivatives of a hierarchical 1D basis at point x
CalcBasis(const int p,const double x,double * u,double * d,double * dd)2074    static void CalcBasis(const int p, const double x, double *u, double *d,
2075                          double *dd)
2076    // { CalcMono(p, x, u, d); }
2077    // { CalcBernstein(p, x, u, d); }
2078    // { CalcLegendre(p, x, u, d); }
2079    { CalcChebyshev(p, x, u, d, dd); }
2080 
2081    /// Evaluate a representation of a Delta function at point x
CalcDelta(const int p,const double x)2082    static double CalcDelta(const int p, const double x)
2083    { return pow(x, (double) p); }
2084 
2085    /** @brief Compute the points for the Chebyshev polynomials of order @a p
2086        and place them in the already allocated @a x array. */
2087    static void ChebyshevPoints(const int p, double *x);
2088 
2089    /** @brief Compute the @a p terms in the expansion of the binomial (x + y)^p
2090        and store them in the already allocated @a u array. */
2091    static void CalcBinomTerms(const int p, const double x, const double y,
2092                               double *u);
2093    /** @brief Compute the terms in the expansion of the binomial (x + y)^p and
2094        their derivatives with respect to x assuming that dy/dx = -1.  Store the
2095        results in the already allocated @a u and @a d arrays.*/
2096    static void CalcBinomTerms(const int p, const double x, const double y,
2097                               double *u, double *d);
2098    /** @brief Compute the derivatives (w.r.t. x) of the terms in the expansion
2099        of the binomial (x + y)^p assuming that dy/dx = -1.  Store the results
2100        in the already allocated @a d array.*/
2101    static void CalcDBinomTerms(const int p, const double x, const double y,
2102                                double *d);
2103 
2104    /** @brief Compute the values of the Bernstein basis functions of order
2105        @a p at coordinate @a x and store the results in the already allocated
2106        @a u array. */
CalcBernstein(const int p,const double x,double * u)2107    static void CalcBernstein(const int p, const double x, double *u)
2108    { CalcBinomTerms(p, x, 1. - x, u); }
2109 
2110    /** @brief Compute the values and derivatives of the Bernstein basis functions
2111        of order @a p at coordinate @a x and store the results in the already allocated
2112        @a u and @a d arrays. */
CalcBernstein(const int p,const double x,double * u,double * d)2113    static void CalcBernstein(const int p, const double x, double *u, double *d)
2114    { CalcBinomTerms(p, x, 1. - x, u, d); }
2115 
2116    static void CalcLegendre(const int p, const double x, double *u);
2117    static void CalcLegendre(const int p, const double x, double *u, double *d);
2118 
2119    ~Poly_1D();
2120 };
2121 
2122 extern Poly_1D poly1d;
2123 
2124 
2125 /// An element defined as an ND tensor product of 1D elements on a segment,
2126 /// square, or cube
2127 class TensorBasisElement
2128 {
2129 protected:
2130    int b_type;
2131    Array<int> dof_map;
2132    Poly_1D::Basis &basis1d;
2133    Array<int> inv_dof_map;
2134 
2135 public:
2136    enum DofMapType
2137    {
2138       L2_DOF_MAP = 0,
2139       H1_DOF_MAP = 1,
2140       Sr_DOF_MAP = 2,  // Sr = Serendipity
2141    };
2142 
2143    TensorBasisElement(const int dims, const int p, const int btype,
2144                       const DofMapType dmtype);
2145 
GetBasisType() const2146    int GetBasisType() const { return b_type; }
2147 
GetBasis1D() const2148    const Poly_1D::Basis& GetBasis1D() const { return basis1d; }
2149 
2150    /** @brief Get an Array<int> that maps lexicographically ordered indices to
2151        the indices of the respective nodes/dofs/basis functions. If the dofs are
2152        ordered lexicographically, i.e. the mapping is identity, the returned
2153        Array will be empty. */
GetDofMap() const2154    const Array<int> &GetDofMap() const { return dof_map; }
2155 
GetTensorProductGeometry(int dim)2156    static Geometry::Type GetTensorProductGeometry(int dim)
2157    {
2158       switch (dim)
2159       {
2160          case 1: return Geometry::SEGMENT;
2161          case 2: return Geometry::SQUARE;
2162          case 3: return Geometry::CUBE;
2163          default:
2164             MFEM_ABORT("invalid dimension: " << dim);
2165             return Geometry::INVALID;
2166       }
2167    }
2168 
2169    /// Return @a base raised to the power @a dim.
Pow(int base,int dim)2170    static int Pow(int base, int dim)
2171    {
2172       switch (dim)
2173       {
2174          case 1: return base;
2175          case 2: return base*base;
2176          case 3: return base*base*base;
2177          default: MFEM_ABORT("invalid dimension: " << dim); return -1;
2178       }
2179    }
2180 };
2181 
2182 class NodalTensorFiniteElement : public NodalFiniteElement,
2183    public TensorBasisElement
2184 {
2185 public:
2186    NodalTensorFiniteElement(const int dims, const int p, const int btype,
2187                             const DofMapType dmtype);
2188 
GetDofToQuad(const IntegrationRule & ir,DofToQuad::Mode mode) const2189    const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
2190                                  DofToQuad::Mode mode) const
2191    {
2192       return (mode == DofToQuad::FULL) ?
2193              ScalarFiniteElement::GetDofToQuad(ir, mode) :
2194              ScalarFiniteElement::GetTensorDofToQuad(*this, ir, mode);
2195    }
2196 
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const2197    virtual void GetTransferMatrix(const FiniteElement &fe,
2198                                   ElementTransformation &Trans,
2199                                   DenseMatrix &I) const
2200    {
2201       if (basis1d.IsIntegratedType())
2202       {
2203          CheckScalarFE(fe).ScalarLocalInterpolation(Trans, I, *this);
2204       }
2205       else
2206       {
2207          NodalFiniteElement::GetTransferMatrix(fe, Trans, I);
2208       }
2209    }
2210 };
2211 
2212 class PositiveTensorFiniteElement : public PositiveFiniteElement,
2213    public TensorBasisElement
2214 {
2215 public:
2216    PositiveTensorFiniteElement(const int dims, const int p,
2217                                const DofMapType dmtype);
2218 
GetDofToQuad(const IntegrationRule & ir,DofToQuad::Mode mode) const2219    const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
2220                                  DofToQuad::Mode mode) const
2221    {
2222       return (mode == DofToQuad::FULL) ?
2223              ScalarFiniteElement::GetDofToQuad(ir, mode) :
2224              ScalarFiniteElement::GetTensorDofToQuad(*this, ir, mode);
2225    }
2226 };
2227 
2228 class VectorTensorFiniteElement : public VectorFiniteElement,
2229    public TensorBasisElement
2230 {
2231 private:
2232    mutable Array<DofToQuad*> dof2quad_array_open;
2233 
2234 protected:
2235    Poly_1D::Basis &cbasis1d, &obasis1d;
2236 
2237 public:
2238    VectorTensorFiniteElement(const int dims, const int d, const int p,
2239                              const int cbtype, const int obtype,
2240                              const int M, const DofMapType dmtype);
2241 
2242    // For 1D elements: there is only an "open basis", no "closed basis"
2243    VectorTensorFiniteElement(const int dims, const int d, const int p,
2244                              const int obtype, const int M,
2245                              const DofMapType dmtype);
2246 
2247    const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
2248                                  DofToQuad::Mode mode) const;
2249 
2250    const DofToQuad &GetDofToQuadOpen(const IntegrationRule &ir,
2251                                      DofToQuad::Mode mode) const;
2252 
2253    const DofToQuad &GetTensorDofToQuad(const IntegrationRule &ir,
2254                                        DofToQuad::Mode mode,
2255                                        const bool closed) const;
2256 
2257    ~VectorTensorFiniteElement();
2258 };
2259 
2260 /// Arbitrary H1 elements in 1D
2261 class H1_SegmentElement : public NodalTensorFiniteElement
2262 {
2263 private:
2264 #ifndef MFEM_THREAD_SAFE
2265    mutable Vector shape_x, dshape_x, d2shape_x;
2266 #endif
2267 
2268 public:
2269    /// Construct the H1_SegmentElement of order @a p and BasisType @a btype
2270    H1_SegmentElement(const int p, const int btype = BasisType::GaussLobatto);
2271    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2272    virtual void CalcDShape(const IntegrationPoint &ip,
2273                            DenseMatrix &dshape) const;
2274    virtual void CalcHessian(const IntegrationPoint &ip,
2275                             DenseMatrix &Hessian) const;
2276    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2277 };
2278 
2279 
2280 /// Arbitrary H1 elements in 2D on a square
2281 class H1_QuadrilateralElement : public NodalTensorFiniteElement
2282 {
2283 private:
2284 #ifndef MFEM_THREAD_SAFE
2285    mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
2286 #endif
2287 
2288 public:
2289    /// Construct the H1_QuadrilateralElement of order @a p and BasisType @a btype
2290    H1_QuadrilateralElement(const int p,
2291                            const int btype = BasisType::GaussLobatto);
2292    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2293    virtual void CalcDShape(const IntegrationPoint &ip,
2294                            DenseMatrix &dshape) const;
2295    virtual void CalcHessian(const IntegrationPoint &ip,
2296                             DenseMatrix &Hessian) const;
2297    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2298 };
2299 
2300 
2301 /// Arbitrary H1 elements in 3D on a cube
2302 class H1_HexahedronElement : public NodalTensorFiniteElement
2303 {
2304 private:
2305 #ifndef MFEM_THREAD_SAFE
2306    mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z,
2307            d2shape_x, d2shape_y, d2shape_z;
2308 #endif
2309 
2310 public:
2311    /// Construct the H1_HexahedronElement of order @a p and BasisType @a btype
2312    H1_HexahedronElement(const int p, const int btype = BasisType::GaussLobatto);
2313    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2314    virtual void CalcDShape(const IntegrationPoint &ip,
2315                            DenseMatrix &dshape) const;
2316    virtual void CalcHessian(const IntegrationPoint &ip,
2317                             DenseMatrix &Hessian) const;
2318    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2319 };
2320 
2321 /// Arbitrary order H1 elements in 1D utilizing the Bernstein basis
2322 class H1Pos_SegmentElement : public PositiveTensorFiniteElement
2323 {
2324 private:
2325 #ifndef MFEM_THREAD_SAFE
2326    // This is to share scratch space between invocations, which helps speed
2327    // things up, but with OpenMP, we need one copy per thread. Right now, we
2328    // solve this by allocating this space within each function call every time
2329    // we call it. Alternatively, we should do some sort thread private thing.
2330    // Brunner, Jan 2014
2331    mutable Vector shape_x, dshape_x;
2332 #endif
2333 
2334 public:
2335    /// Construct the H1Pos_SegmentElement of order @a p
2336    H1Pos_SegmentElement(const int p);
2337    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2338    virtual void CalcDShape(const IntegrationPoint &ip,
2339                            DenseMatrix &dshape) const;
2340    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2341 };
2342 
2343 
2344 /// Arbitrary order H1 elements in 2D utilizing the Bernstein basis on a square
2345 class H1Pos_QuadrilateralElement : public PositiveTensorFiniteElement
2346 {
2347 private:
2348 #ifndef MFEM_THREAD_SAFE
2349    // See comment in H1Pos_SegmentElement
2350    mutable Vector shape_x, shape_y, dshape_x, dshape_y;
2351 #endif
2352 
2353 public:
2354    /// Construct the H1Pos_QuadrilateralElement of order @a p
2355    H1Pos_QuadrilateralElement(const int p);
2356    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2357    virtual void CalcDShape(const IntegrationPoint &ip,
2358                            DenseMatrix &dshape) const;
2359    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2360 };
2361 
2362 
2363 /// Arbitrary order H1 serendipity elements in 2D on a quad
2364 class H1Ser_QuadrilateralElement : public ScalarFiniteElement
2365 {
2366 public:
2367    /// Construct the H1Ser_QuadrilateralElement of order @a p
2368    H1Ser_QuadrilateralElement(const int p);
2369    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2370    virtual void CalcDShape(const IntegrationPoint &ip,
2371                            DenseMatrix &dshape) const;
2372    virtual void GetLocalInterpolation(ElementTransformation &Trans,
2373                                       DenseMatrix &I) const;
2374    using FiniteElement::Project;
2375 };
2376 
2377 /// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a cube
2378 class H1Pos_HexahedronElement : public PositiveTensorFiniteElement
2379 {
2380 private:
2381 #ifndef MFEM_THREAD_SAFE
2382    // See comment in H1Pos_SegementElement.
2383    mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z;
2384 #endif
2385 
2386 public:
2387    /// Construct the H1Pos_HexahedronElement of order @a p
2388    H1Pos_HexahedronElement(const int p);
2389    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2390    virtual void CalcDShape(const IntegrationPoint &ip,
2391                            DenseMatrix &dshape) const;
2392    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2393 };
2394 
2395 
2396 /// Arbitrary order H1 elements in 2D on a triangle
2397 class H1_TriangleElement : public NodalFiniteElement
2398 {
2399 private:
2400 #ifndef MFEM_THREAD_SAFE
2401    mutable Vector shape_x, shape_y, shape_l, dshape_x, dshape_y, dshape_l, u;
2402    mutable Vector ddshape_x, ddshape_y, ddshape_l;
2403    mutable DenseMatrix du, ddu;
2404 #endif
2405    DenseMatrixInverse Ti;
2406 
2407 public:
2408    /// Construct the H1_TriangleElement of order @a p and BasisType @a btype
2409    H1_TriangleElement(const int p, const int btype = BasisType::GaussLobatto);
2410    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2411    virtual void CalcDShape(const IntegrationPoint &ip,
2412                            DenseMatrix &dshape) const;
2413    virtual void CalcHessian(const IntegrationPoint &ip,
2414                             DenseMatrix &ddshape) const;
2415 };
2416 
2417 
2418 /// Arbitrary order H1 elements in 3D  on a tetrahedron
2419 class H1_TetrahedronElement : public NodalFiniteElement
2420 {
2421 private:
2422 #ifndef MFEM_THREAD_SAFE
2423    mutable Vector shape_x, shape_y, shape_z, shape_l;
2424    mutable Vector dshape_x, dshape_y, dshape_z, dshape_l, u;
2425    mutable Vector ddshape_x, ddshape_y, ddshape_z, ddshape_l;
2426    mutable DenseMatrix du, ddu;
2427 #endif
2428    DenseMatrixInverse Ti;
2429 
2430 public:
2431    /// Construct the H1_TetrahedronElement of order @a p and BasisType @a btype
2432    H1_TetrahedronElement(const int p,
2433                          const int btype = BasisType::GaussLobatto);
2434    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2435    virtual void CalcDShape(const IntegrationPoint &ip,
2436                            DenseMatrix &dshape) const;
2437    virtual void CalcHessian(const IntegrationPoint &ip,
2438                             DenseMatrix &ddshape) const;
2439 };
2440 
2441 
2442 /// Arbitrary order H1 elements in 2D utilizing the Bernstein basis on a triangle
2443 class H1Pos_TriangleElement : public PositiveFiniteElement
2444 {
2445 protected:
2446 #ifndef MFEM_THREAD_SAFE
2447    mutable Vector m_shape, dshape_1d;
2448    mutable DenseMatrix m_dshape;
2449 #endif
2450    Array<int> dof_map;
2451 
2452 public:
2453    /// Construct the H1Pos_TriangleElement of order @a p
2454    H1Pos_TriangleElement(const int p);
2455 
2456    // The size of shape is (p+1)(p+2)/2 (dof).
2457    static void CalcShape(const int p, const double x, const double y,
2458                          double *shape);
2459 
2460    // The size of dshape_1d is p+1; the size of dshape is (dof x dim).
2461    static void CalcDShape(const int p, const double x, const double y,
2462                           double *dshape_1d, double *dshape);
2463 
2464    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2465    virtual void CalcDShape(const IntegrationPoint &ip,
2466                            DenseMatrix &dshape) const;
2467 };
2468 
2469 
2470 /// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a
2471 /// tetrahedron
2472 class H1Pos_TetrahedronElement : public PositiveFiniteElement
2473 {
2474 protected:
2475 #ifndef MFEM_THREAD_SAFE
2476    mutable Vector m_shape, dshape_1d;
2477    mutable DenseMatrix m_dshape;
2478 #endif
2479    Array<int> dof_map;
2480 
2481 public:
2482    /// Construct the H1Pos_TetrahedronElement of order @a p
2483    H1Pos_TetrahedronElement(const int p);
2484 
2485    // The size of shape is (p+1)(p+2)(p+3)/6 (dof).
2486    static void CalcShape(const int p, const double x, const double y,
2487                          const double z, double *shape);
2488 
2489    // The size of dshape_1d is p+1; the size of dshape is (dof x dim).
2490    static void CalcDShape(const int p, const double x, const double y,
2491                           const double z, double *dshape_1d, double *dshape);
2492 
2493    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2494    virtual void CalcDShape(const IntegrationPoint &ip,
2495                            DenseMatrix &dshape) const;
2496 };
2497 
2498 
2499 /// Arbitrary order H1 elements in 3D on a wedge
2500 class H1_WedgeElement : public NodalFiniteElement
2501 {
2502 private:
2503 #ifndef MFEM_THREAD_SAFE
2504    mutable Vector t_shape, s_shape;
2505    mutable DenseMatrix t_dshape, s_dshape;
2506 #endif
2507    Array<int> t_dof, s_dof;
2508 
2509    H1_TriangleElement TriangleFE;
2510    H1_SegmentElement  SegmentFE;
2511 
2512 public:
2513    /// Construct the H1_WedgeElement of order @a p and BasisType @a btype
2514    H1_WedgeElement(const int p,
2515                    const int btype = BasisType::GaussLobatto);
2516    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2517    virtual void CalcDShape(const IntegrationPoint &ip,
2518                            DenseMatrix &dshape) const;
2519 };
2520 
2521 /// Class for linear FE on wedge
2522 class BiLinear3DFiniteElement : public H1_WedgeElement
2523 {
2524 public:
2525    /// Construct a linear FE on wedge
BiLinear3DFiniteElement()2526    BiLinear3DFiniteElement() : H1_WedgeElement(1) {}
2527 };
2528 
2529 /// Class for quadratic FE on wedge
2530 class BiQuadratic3DFiniteElement : public H1_WedgeElement
2531 {
2532 public:
2533    /// Construct a quadratic FE on wedge
BiQuadratic3DFiniteElement()2534    BiQuadratic3DFiniteElement() : H1_WedgeElement(2) {}
2535 };
2536 
2537 /// Class for cubic FE on wedge
2538 class BiCubic3DFiniteElement : public H1_WedgeElement
2539 {
2540 public:
2541    /// Construct a cubic FE on wedge
BiCubic3DFiniteElement()2542    BiCubic3DFiniteElement() : H1_WedgeElement(3) {}
2543 };
2544 
2545 /// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a wedge
2546 class H1Pos_WedgeElement : public PositiveFiniteElement
2547 {
2548 protected:
2549 #ifndef MFEM_THREAD_SAFE
2550    mutable Vector t_shape, s_shape;
2551    mutable DenseMatrix t_dshape, s_dshape;
2552 #endif
2553    Array<int> t_dof, s_dof;
2554 
2555    H1Pos_TriangleElement TriangleFE;
2556    H1Pos_SegmentElement  SegmentFE;
2557 
2558 public:
2559    /// Construct the H1Pos_WedgeElement of order @a p
2560    H1Pos_WedgeElement(const int p);
2561 
2562    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2563    virtual void CalcDShape(const IntegrationPoint &ip,
2564                            DenseMatrix &dshape) const;
2565 };
2566 
2567 
2568 /// Arbitrary L2 elements in 1D on a segment
2569 class L2_SegmentElement : public NodalTensorFiniteElement
2570 {
2571 private:
2572 #ifndef MFEM_THREAD_SAFE
2573    mutable Vector shape_x, dshape_x;
2574 #endif
2575 
2576 public:
2577    /// Construct the L2_SegmentElement of order @a p and BasisType @a btype
2578    L2_SegmentElement(const int p, const int btype = BasisType::GaussLegendre);
2579    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2580    virtual void CalcDShape(const IntegrationPoint &ip,
2581                            DenseMatrix &dshape) const;
2582    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2583 };
2584 
2585 /// Arbitrary order L2 elements in 1D utilizing the Bernstein basis on a segment
2586 class L2Pos_SegmentElement : public PositiveTensorFiniteElement
2587 {
2588 private:
2589 #ifndef MFEM_THREAD_SAFE
2590    mutable Vector shape_x, dshape_x;
2591 #endif
2592 
2593 public:
2594    /// Construct the L2Pos_SegmentElement of order @a p
2595    L2Pos_SegmentElement(const int p);
2596    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2597    virtual void CalcDShape(const IntegrationPoint &ip,
2598                            DenseMatrix &dshape) const;
2599    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2600 };
2601 
2602 
2603 /// Arbitrary order L2 elements in 2D on a square
2604 class L2_QuadrilateralElement : public NodalTensorFiniteElement
2605 {
2606 private:
2607 #ifndef MFEM_THREAD_SAFE
2608    mutable Vector shape_x, shape_y, dshape_x, dshape_y;
2609 #endif
2610 
2611 public:
2612    /// Construct the L2_QuadrilateralElement of order @a p and BasisType @a btype
2613    L2_QuadrilateralElement(const int p,
2614                            const int btype = BasisType::GaussLegendre);
2615    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2616    virtual void CalcDShape(const IntegrationPoint &ip,
2617                            DenseMatrix &dshape) const;
2618    virtual void ProjectDelta(int vertex, Vector &dofs) const;
ProjectCurl(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & curl) const2619    virtual void ProjectCurl(const FiniteElement &fe,
2620                             ElementTransformation &Trans,
2621                             DenseMatrix &curl) const
2622    { ProjectCurl_2D(fe, Trans, curl); }
2623 };
2624 
2625 /// Arbitrary order L2 elements in 2D utilizing the Bernstein basis on a square
2626 class L2Pos_QuadrilateralElement : public PositiveTensorFiniteElement
2627 {
2628 private:
2629 #ifndef MFEM_THREAD_SAFE
2630    mutable Vector shape_x, shape_y, dshape_x, dshape_y;
2631 #endif
2632 
2633 public:
2634    /// Construct the L2Pos_QuadrilateralElement of order @a p
2635    L2Pos_QuadrilateralElement(const int p);
2636    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2637    virtual void CalcDShape(const IntegrationPoint &ip,
2638                            DenseMatrix &dshape) const;
2639    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2640 };
2641 
2642 /// Arbitrary order L2 elements in 3D on a cube
2643 class L2_HexahedronElement : public NodalTensorFiniteElement
2644 {
2645 private:
2646 #ifndef MFEM_THREAD_SAFE
2647    mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z;
2648 #endif
2649 
2650 public:
2651    /// Construct the L2_HexahedronElement of order @a p and BasisType @a btype
2652    L2_HexahedronElement(const int p,
2653                         const int btype = BasisType::GaussLegendre);
2654    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2655    virtual void CalcDShape(const IntegrationPoint &ip,
2656                            DenseMatrix &dshape) const;
2657    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2658 };
2659 
2660 
2661 /// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a cube
2662 class L2Pos_HexahedronElement : public PositiveTensorFiniteElement
2663 {
2664 private:
2665 #ifndef MFEM_THREAD_SAFE
2666    mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z;
2667 #endif
2668 
2669 public:
2670    /// Construct the L2Pos_HexahedronElement of order @a p
2671    L2Pos_HexahedronElement(const int p);
2672    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2673    virtual void CalcDShape(const IntegrationPoint &ip,
2674                            DenseMatrix &dshape) const;
2675    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2676 };
2677 
2678 
2679 /// Arbitrary order L2 elements in 2D on a triangle
2680 class L2_TriangleElement : public NodalFiniteElement
2681 {
2682 private:
2683 #ifndef MFEM_THREAD_SAFE
2684    mutable Vector shape_x, shape_y, shape_l, dshape_x, dshape_y, dshape_l, u;
2685    mutable DenseMatrix du;
2686 #endif
2687    DenseMatrixInverse Ti;
2688 
2689 public:
2690    /// Construct the L2_TriangleElement of order @a p and BasisType @a btype
2691    L2_TriangleElement(const int p,
2692                       const int btype = BasisType::GaussLegendre);
2693    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2694    virtual void CalcDShape(const IntegrationPoint &ip,
2695                            DenseMatrix &dshape) const;
2696    virtual void ProjectDelta(int vertex, Vector &dofs) const;
ProjectCurl(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & curl) const2697    virtual void ProjectCurl(const FiniteElement &fe,
2698                             ElementTransformation &Trans,
2699                             DenseMatrix &curl) const
2700    { ProjectCurl_2D(fe, Trans, curl); }
2701 };
2702 
2703 /// Arbitrary order L2 elements in 2D utilizing the Bernstein basis on a triangle
2704 class L2Pos_TriangleElement : public PositiveFiniteElement
2705 {
2706 private:
2707 #ifndef MFEM_THREAD_SAFE
2708    mutable Vector dshape_1d;
2709 #endif
2710 
2711 public:
2712    /// Construct the L2Pos_TriangleElement of order @a p
2713    L2Pos_TriangleElement(const int p);
2714    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2715    virtual void CalcDShape(const IntegrationPoint &ip,
2716                            DenseMatrix &dshape) const;
2717    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2718 };
2719 
2720 
2721 /// Arbitrary order L2 elements in 3D on a tetrahedron
2722 class L2_TetrahedronElement : public NodalFiniteElement
2723 {
2724 private:
2725 #ifndef MFEM_THREAD_SAFE
2726    mutable Vector shape_x, shape_y, shape_z, shape_l;
2727    mutable Vector dshape_x, dshape_y, dshape_z, dshape_l, u;
2728    mutable DenseMatrix du;
2729 #endif
2730    DenseMatrixInverse Ti;
2731 
2732 public:
2733    /// Construct the L2_TetrahedronElement of order @a p and BasisType @a btype
2734    L2_TetrahedronElement(const int p,
2735                          const int btype = BasisType::GaussLegendre);
2736    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2737    virtual void CalcDShape(const IntegrationPoint &ip,
2738                            DenseMatrix &dshape) const;
2739    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2740 };
2741 
2742 
2743 /// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a
2744 /// tetrahedron
2745 class L2Pos_TetrahedronElement : public PositiveFiniteElement
2746 {
2747 private:
2748 #ifndef MFEM_THREAD_SAFE
2749    mutable Vector dshape_1d;
2750 #endif
2751 
2752 public:
2753    /// Construct the L2Pos_TetrahedronElement of order @a p
2754    L2Pos_TetrahedronElement(const int p);
2755    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2756    virtual void CalcDShape(const IntegrationPoint &ip,
2757                            DenseMatrix &dshape) const;
2758    virtual void ProjectDelta(int vertex, Vector &dofs) const;
2759 };
2760 
2761 
2762 /// Arbitrary order L2 elements in 3D on a wedge
2763 class L2_WedgeElement : public NodalFiniteElement
2764 {
2765 private:
2766 #ifndef MFEM_THREAD_SAFE
2767    mutable Vector t_shape, s_shape;
2768    mutable DenseMatrix t_dshape, s_dshape;
2769 #endif
2770    Array<int> t_dof, s_dof;
2771 
2772    L2_TriangleElement TriangleFE;
2773    L2_SegmentElement  SegmentFE;
2774 
2775 public:
2776    /// Construct the L2_WedgeElement of order @a p and BasisType @a btype
2777    L2_WedgeElement(const int p,
2778                    const int btype = BasisType::GaussLegendre);
2779    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2780    virtual void CalcDShape(const IntegrationPoint &ip,
2781                            DenseMatrix &dshape) const;
2782 };
2783 
2784 /// A 0th order L2 element on a Wedge
2785 class P0WedgeFiniteElement : public L2_WedgeElement
2786 {
2787 public:
2788    /// Construct the P0WedgeFiniteElement
P0WedgeFiniteElement()2789    P0WedgeFiniteElement () : L2_WedgeElement(0) {}
2790 };
2791 
2792 /// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a wedge
2793 class L2Pos_WedgeElement : public PositiveFiniteElement
2794 {
2795 protected:
2796 #ifndef MFEM_THREAD_SAFE
2797    mutable Vector t_shape, s_shape;
2798    mutable DenseMatrix t_dshape, s_dshape;
2799 #endif
2800    Array<int> t_dof, s_dof;
2801 
2802    L2Pos_TriangleElement TriangleFE;
2803    L2Pos_SegmentElement  SegmentFE;
2804 
2805 public:
2806    /// Construct the L2Pos_WedgeElement of order @a p
2807    L2Pos_WedgeElement(const int p);
2808 
2809    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
2810    virtual void CalcDShape(const IntegrationPoint &ip,
2811                            DenseMatrix &dshape) const;
2812 };
2813 
2814 /// Arbitrary order Raviart-Thomas elements in 2D on a square
2815 class RT_QuadrilateralElement : public VectorTensorFiniteElement
2816 {
2817 private:
2818    static const double nk[8];
2819 
2820 #ifndef MFEM_THREAD_SAFE
2821    mutable Vector shape_cx, shape_ox, shape_cy, shape_oy;
2822    mutable Vector dshape_cx, dshape_cy;
2823 #endif
2824    Array<int> dof2nk;
2825    const double *cp;
2826 
2827 public:
2828    /** @brief Construct the RT_QuadrilateralElement of order @a p and closed and
2829        open BasisType @a cb_type and @a ob_type */
2830    RT_QuadrilateralElement(const int p,
2831                            const int cb_type = BasisType::GaussLobatto,
2832                            const int ob_type = BasisType::GaussLegendre);
2833    virtual void CalcVShape(const IntegrationPoint &ip,
2834                            DenseMatrix &shape) const;
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const2835    virtual void CalcVShape(ElementTransformation &Trans,
2836                            DenseMatrix &shape) const
2837    { CalcVShape_RT(Trans, shape); }
2838    virtual void CalcDivShape(const IntegrationPoint &ip,
2839                              Vector &divshape) const;
GetLocalInterpolation(ElementTransformation & Trans,DenseMatrix & I) const2840    virtual void GetLocalInterpolation(ElementTransformation &Trans,
2841                                       DenseMatrix &I) const
2842    { LocalInterpolation_RT(*this, nk, dof2nk, Trans, I); }
GetLocalRestriction(ElementTransformation & Trans,DenseMatrix & R) const2843    virtual void GetLocalRestriction(ElementTransformation &Trans,
2844                                     DenseMatrix &R) const
2845    { LocalRestriction_RT(nk, dof2nk, Trans, R); }
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const2846    virtual void GetTransferMatrix(const FiniteElement &fe,
2847                                   ElementTransformation &Trans,
2848                                   DenseMatrix &I) const
2849    { LocalInterpolation_RT(CheckVectorFE(fe), nk, dof2nk, Trans, I); }
2850    using FiniteElement::Project;
Project(VectorCoefficient & vc,ElementTransformation & Trans,Vector & dofs) const2851    virtual void Project(VectorCoefficient &vc,
2852                         ElementTransformation &Trans, Vector &dofs) const
2853    {
2854       if (obasis1d.IsIntegratedType()) { ProjectIntegrated(vc, Trans, dofs); }
2855       else { Project_RT(nk, dof2nk, vc, Trans, dofs); }
2856    }
ProjectFromNodes(Vector & vc,ElementTransformation & Trans,Vector & dofs) const2857    virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
2858                                  Vector &dofs) const
2859    { Project_RT(nk, dof2nk, vc, Trans, dofs); }
ProjectMatrixCoefficient(MatrixCoefficient & mc,ElementTransformation & T,Vector & dofs) const2860    virtual void ProjectMatrixCoefficient(
2861       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
2862    { ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
Project(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const2863    virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
2864                         DenseMatrix &I) const
2865    { Project_RT(nk, dof2nk, fe, Trans, I); }
2866    // Gradient + rotation = Curl: H1 -> H(div)
ProjectGrad(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & grad) const2867    virtual void ProjectGrad(const FiniteElement &fe,
2868                             ElementTransformation &Trans,
2869                             DenseMatrix &grad) const
2870    { ProjectGrad_RT(nk, dof2nk, fe, Trans, grad); }
2871    // Curl = Gradient + rotation: H1 -> H(div)
ProjectCurl(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & curl) const2872    virtual void ProjectCurl(const FiniteElement &fe,
2873                             ElementTransformation &Trans,
2874                             DenseMatrix &curl) const
2875    { ProjectGrad_RT(nk, dof2nk, fe, Trans, curl); }
2876 
2877 protected:
2878    void ProjectIntegrated(VectorCoefficient &vc, ElementTransformation &Trans,
2879                           Vector &dofs) const;
2880 };
2881 
2882 
2883 /// Arbitrary order Raviart-Thomas elements in 3D on a cube
2884 class RT_HexahedronElement : public VectorTensorFiniteElement
2885 {
2886    static const double nk[18];
2887 
2888 #ifndef MFEM_THREAD_SAFE
2889    mutable Vector shape_cx, shape_ox, shape_cy, shape_oy, shape_cz, shape_oz;
2890    mutable Vector dshape_cx, dshape_cy, dshape_cz;
2891 #endif
2892    Array<int> dof2nk;
2893    const double *cp;
2894 
2895 public:
2896    /** @brief Construct the RT_HexahedronElement of order @a p and closed and
2897        open BasisType @a cb_type and @a ob_type */
2898    RT_HexahedronElement(const int p,
2899                         const int cb_type = BasisType::GaussLobatto,
2900                         const int ob_type = BasisType::GaussLegendre);
2901 
2902    virtual void CalcVShape(const IntegrationPoint &ip,
2903                            DenseMatrix &shape) const;
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const2904    virtual void CalcVShape(ElementTransformation &Trans,
2905                            DenseMatrix &shape) const
2906    { CalcVShape_RT(Trans, shape); }
2907    virtual void CalcDivShape(const IntegrationPoint &ip,
2908                              Vector &divshape) const;
GetLocalInterpolation(ElementTransformation & Trans,DenseMatrix & I) const2909    virtual void GetLocalInterpolation(ElementTransformation &Trans,
2910                                       DenseMatrix &I) const
2911    { LocalInterpolation_RT(*this, nk, dof2nk, Trans, I); }
GetLocalRestriction(ElementTransformation & Trans,DenseMatrix & R) const2912    virtual void GetLocalRestriction(ElementTransformation &Trans,
2913                                     DenseMatrix &R) const
2914    { LocalRestriction_RT(nk, dof2nk, Trans, R); }
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const2915    virtual void GetTransferMatrix(const FiniteElement &fe,
2916                                   ElementTransformation &Trans,
2917                                   DenseMatrix &I) const
2918    { LocalInterpolation_RT(CheckVectorFE(fe), nk, dof2nk, Trans, I); }
2919    using FiniteElement::Project;
Project(VectorCoefficient & vc,ElementTransformation & Trans,Vector & dofs) const2920    virtual void Project(VectorCoefficient &vc,
2921                         ElementTransformation &Trans, Vector &dofs) const
2922    {
2923       if (obasis1d.IsIntegratedType()) { ProjectIntegrated(vc, Trans, dofs); }
2924       else { Project_RT(nk, dof2nk, vc, Trans, dofs); }
2925    }
ProjectFromNodes(Vector & vc,ElementTransformation & Trans,Vector & dofs) const2926    virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
2927                                  Vector &dofs) const
2928    { Project_RT(nk, dof2nk, vc, Trans, dofs); }
ProjectMatrixCoefficient(MatrixCoefficient & mc,ElementTransformation & T,Vector & dofs) const2929    virtual void ProjectMatrixCoefficient(
2930       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
2931    { ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
Project(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const2932    virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
2933                         DenseMatrix &I) const
2934    { Project_RT(nk, dof2nk, fe, Trans, I); }
ProjectCurl(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & curl) const2935    virtual void ProjectCurl(const FiniteElement &fe,
2936                             ElementTransformation &Trans,
2937                             DenseMatrix &curl) const
2938    { ProjectCurl_RT(nk, dof2nk, fe, Trans, curl); }
2939 
2940 protected:
2941    void ProjectIntegrated(VectorCoefficient &vc,
2942                           ElementTransformation &Trans,
2943                           Vector &dofs) const;
2944 };
2945 
2946 
2947 /// Arbitrary order Raviart-Thomas elements in 2D on a triangle
2948 class RT_TriangleElement : public VectorFiniteElement
2949 {
2950    static const double nk[6], c;
2951 
2952 #ifndef MFEM_THREAD_SAFE
2953    mutable Vector shape_x, shape_y, shape_l;
2954    mutable Vector dshape_x, dshape_y, dshape_l;
2955    mutable DenseMatrix u;
2956    mutable Vector divu;
2957 #endif
2958    Array<int> dof2nk;
2959    DenseMatrixInverse Ti;
2960 
2961 public:
2962    /// Construct the RT_TriangleElement of order @a p
2963    RT_TriangleElement(const int p);
2964    virtual void CalcVShape(const IntegrationPoint &ip,
2965                            DenseMatrix &shape) const;
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const2966    virtual void CalcVShape(ElementTransformation &Trans,
2967                            DenseMatrix &shape) const
2968    { CalcVShape_RT(Trans, shape); }
2969    virtual void CalcDivShape(const IntegrationPoint &ip,
2970                              Vector &divshape) const;
GetLocalInterpolation(ElementTransformation & Trans,DenseMatrix & I) const2971    virtual void GetLocalInterpolation(ElementTransformation &Trans,
2972                                       DenseMatrix &I) const
2973    { LocalInterpolation_RT(*this, nk, dof2nk, Trans, I); }
GetLocalRestriction(ElementTransformation & Trans,DenseMatrix & R) const2974    virtual void GetLocalRestriction(ElementTransformation &Trans,
2975                                     DenseMatrix &R) const
2976    { LocalRestriction_RT(nk, dof2nk, Trans, R); }
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const2977    virtual void GetTransferMatrix(const FiniteElement &fe,
2978                                   ElementTransformation &Trans,
2979                                   DenseMatrix &I) const
2980    { LocalInterpolation_RT(CheckVectorFE(fe), nk, dof2nk, Trans, I); }
2981    using FiniteElement::Project;
Project(VectorCoefficient & vc,ElementTransformation & Trans,Vector & dofs) const2982    virtual void Project(VectorCoefficient &vc,
2983                         ElementTransformation &Trans, Vector &dofs) const
2984    { Project_RT(nk, dof2nk, vc, Trans, dofs); }
ProjectFromNodes(Vector & vc,ElementTransformation & Trans,Vector & dofs) const2985    virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
2986                                  Vector &dofs) const
2987    { Project_RT(nk, dof2nk, vc, Trans, dofs); }
ProjectMatrixCoefficient(MatrixCoefficient & mc,ElementTransformation & T,Vector & dofs) const2988    virtual void ProjectMatrixCoefficient(
2989       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
2990    { ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
Project(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const2991    virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
2992                         DenseMatrix &I) const
2993    { Project_RT(nk, dof2nk, fe, Trans, I); }
2994    // Gradient + rotation = Curl: H1 -> H(div)
ProjectGrad(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & grad) const2995    virtual void ProjectGrad(const FiniteElement &fe,
2996                             ElementTransformation &Trans,
2997                             DenseMatrix &grad) const
2998    { ProjectGrad_RT(nk, dof2nk, fe, Trans, grad); }
2999    // Curl = Gradient + rotation: H1 -> H(div)
ProjectCurl(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & curl) const3000    virtual void ProjectCurl(const FiniteElement &fe,
3001                             ElementTransformation &Trans,
3002                             DenseMatrix &curl) const
3003    { ProjectGrad_RT(nk, dof2nk, fe, Trans, curl); }
3004 };
3005 
3006 
3007 /// Arbitrary order Raviart-Thomas elements in 3D on a tetrahedron
3008 class RT_TetrahedronElement : public VectorFiniteElement
3009 {
3010    static const double nk[12], c;
3011 
3012 #ifndef MFEM_THREAD_SAFE
3013    mutable Vector shape_x, shape_y, shape_z, shape_l;
3014    mutable Vector dshape_x, dshape_y, dshape_z, dshape_l;
3015    mutable DenseMatrix u;
3016    mutable Vector divu;
3017 #endif
3018    Array<int> dof2nk;
3019    DenseMatrixInverse Ti;
3020 
3021 public:
3022    /// Construct the RT_TetrahedronElement of order @a p
3023    RT_TetrahedronElement(const int p);
3024    virtual void CalcVShape(const IntegrationPoint &ip,
3025                            DenseMatrix &shape) const;
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const3026    virtual void CalcVShape(ElementTransformation &Trans,
3027                            DenseMatrix &shape) const
3028    { CalcVShape_RT(Trans, shape); }
3029    virtual void CalcDivShape(const IntegrationPoint &ip,
3030                              Vector &divshape) const;
GetLocalInterpolation(ElementTransformation & Trans,DenseMatrix & I) const3031    virtual void GetLocalInterpolation(ElementTransformation &Trans,
3032                                       DenseMatrix &I) const
3033    { LocalInterpolation_RT(*this, nk, dof2nk, Trans, I); }
GetLocalRestriction(ElementTransformation & Trans,DenseMatrix & R) const3034    virtual void GetLocalRestriction(ElementTransformation &Trans,
3035                                     DenseMatrix &R) const
3036    { LocalRestriction_RT(nk, dof2nk, Trans, R); }
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3037    virtual void GetTransferMatrix(const FiniteElement &fe,
3038                                   ElementTransformation &Trans,
3039                                   DenseMatrix &I) const
3040    { LocalInterpolation_RT(CheckVectorFE(fe), nk, dof2nk, Trans, I); }
3041    using FiniteElement::Project;
Project(VectorCoefficient & vc,ElementTransformation & Trans,Vector & dofs) const3042    virtual void Project(VectorCoefficient &vc,
3043                         ElementTransformation &Trans, Vector &dofs) const
3044    { Project_RT(nk, dof2nk, vc, Trans, dofs); }
ProjectFromNodes(Vector & vc,ElementTransformation & Trans,Vector & dofs) const3045    virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
3046                                  Vector &dofs) const
3047    { Project_RT(nk, dof2nk, vc, Trans, dofs); }
ProjectMatrixCoefficient(MatrixCoefficient & mc,ElementTransformation & T,Vector & dofs) const3048    virtual void ProjectMatrixCoefficient(
3049       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
3050    { ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
Project(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3051    virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
3052                         DenseMatrix &I) const
3053    { Project_RT(nk, dof2nk, fe, Trans, I); }
ProjectCurl(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & curl) const3054    virtual void ProjectCurl(const FiniteElement &fe,
3055                             ElementTransformation &Trans,
3056                             DenseMatrix &curl) const
3057    { ProjectCurl_RT(nk, dof2nk, fe, Trans, curl); }
3058 };
3059 
3060 
3061 /// Arbitrary order Nedelec elements in 3D on a cube
3062 class ND_HexahedronElement : public VectorTensorFiniteElement
3063 {
3064    static const double tk[18];
3065 #ifndef MFEM_THREAD_SAFE
3066    mutable Vector shape_cx, shape_ox, shape_cy, shape_oy, shape_cz, shape_oz;
3067    mutable Vector dshape_cx, dshape_cy, dshape_cz;
3068 #endif
3069    Array<int> dof2tk;
3070    const double *cp;
3071 
3072 public:
3073    /** @brief Construct the ND_HexahedronElement of order @a p and closed and
3074        open BasisType @a cb_type and @a ob_type */
3075    ND_HexahedronElement(const int p,
3076                         const int cb_type = BasisType::GaussLobatto,
3077                         const int ob_type = BasisType::GaussLegendre);
3078 
3079    virtual void CalcVShape(const IntegrationPoint &ip,
3080                            DenseMatrix &shape) const;
3081 
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const3082    virtual void CalcVShape(ElementTransformation &Trans,
3083                            DenseMatrix &shape) const
3084    { CalcVShape_ND(Trans, shape); }
3085 
3086    virtual void CalcCurlShape(const IntegrationPoint &ip,
3087                               DenseMatrix &curl_shape) const;
3088 
GetLocalInterpolation(ElementTransformation & Trans,DenseMatrix & I) const3089    virtual void GetLocalInterpolation(ElementTransformation &Trans,
3090                                       DenseMatrix &I) const
3091    { LocalInterpolation_ND(*this, tk, dof2tk, Trans, I); }
3092 
GetLocalRestriction(ElementTransformation & Trans,DenseMatrix & R) const3093    virtual void GetLocalRestriction(ElementTransformation &Trans,
3094                                     DenseMatrix &R) const
3095    { LocalRestriction_ND(tk, dof2tk, Trans, R); }
3096 
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3097    virtual void GetTransferMatrix(const FiniteElement &fe,
3098                                   ElementTransformation &Trans,
3099                                   DenseMatrix &I) const
3100    { LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
3101 
3102    using FiniteElement::Project;
3103 
Project(VectorCoefficient & vc,ElementTransformation & Trans,Vector & dofs) const3104    virtual void Project(VectorCoefficient &vc,
3105                         ElementTransformation &Trans, Vector &dofs) const
3106    {
3107       if (obasis1d.IsIntegratedType()) { ProjectIntegrated(vc, Trans, dofs); }
3108       else { Project_ND(tk, dof2tk, vc, Trans, dofs); }
3109    }
3110 
ProjectFromNodes(Vector & vc,ElementTransformation & Trans,Vector & dofs) const3111    virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
3112                                  Vector &dofs) const
3113    { Project_ND(tk, dof2tk, vc, Trans, dofs); }
3114 
ProjectMatrixCoefficient(MatrixCoefficient & mc,ElementTransformation & T,Vector & dofs) const3115    virtual void ProjectMatrixCoefficient(
3116       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
3117    { ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
3118 
Project(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3119    virtual void Project(const FiniteElement &fe,
3120                         ElementTransformation &Trans,
3121                         DenseMatrix &I) const
3122    { Project_ND(tk, dof2tk, fe, Trans, I); }
3123 
ProjectGrad(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & grad) const3124    virtual void ProjectGrad(const FiniteElement &fe,
3125                             ElementTransformation &Trans,
3126                             DenseMatrix &grad) const
3127    { ProjectGrad_ND(tk, dof2tk, fe, Trans, grad); }
3128 
ProjectCurl(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & curl) const3129    virtual void ProjectCurl(const FiniteElement &fe,
3130                             ElementTransformation &Trans,
3131                             DenseMatrix &curl) const
3132    { ProjectCurl_ND(tk, dof2tk, fe, Trans, curl); }
3133 
3134 protected:
3135    void ProjectIntegrated(VectorCoefficient &vc,
3136                           ElementTransformation &Trans,
3137                           Vector &dofs) const;
3138 };
3139 
3140 
3141 /// Arbitrary order Nedelec elements in 2D on a square
3142 class ND_QuadrilateralElement : public VectorTensorFiniteElement
3143 {
3144    static const double tk[8];
3145 
3146 #ifndef MFEM_THREAD_SAFE
3147    mutable Vector shape_cx, shape_ox, shape_cy, shape_oy;
3148    mutable Vector dshape_cx, dshape_cy;
3149 #endif
3150    Array<int> dof2tk;
3151    const double *cp;
3152 
3153 public:
3154    /** @brief Construct the ND_QuadrilateralElement of order @a p and closed and
3155        open BasisType @a cb_type and @a ob_type */
3156    ND_QuadrilateralElement(const int p,
3157                            const int cb_type = BasisType::GaussLobatto,
3158                            const int ob_type = BasisType::GaussLegendre);
3159    virtual void CalcVShape(const IntegrationPoint &ip,
3160                            DenseMatrix &shape) const;
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const3161    virtual void CalcVShape(ElementTransformation &Trans,
3162                            DenseMatrix &shape) const
3163    { CalcVShape_ND(Trans, shape); }
3164    virtual void CalcCurlShape(const IntegrationPoint &ip,
3165                               DenseMatrix &curl_shape) const;
GetLocalInterpolation(ElementTransformation & Trans,DenseMatrix & I) const3166    virtual void GetLocalInterpolation(ElementTransformation &Trans,
3167                                       DenseMatrix &I) const
3168    { LocalInterpolation_ND(*this, tk, dof2tk, Trans, I); }
GetLocalRestriction(ElementTransformation & Trans,DenseMatrix & R) const3169    virtual void GetLocalRestriction(ElementTransformation &Trans,
3170                                     DenseMatrix &R) const
3171    { LocalRestriction_ND(tk, dof2tk, Trans, R); }
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3172    virtual void GetTransferMatrix(const FiniteElement &fe,
3173                                   ElementTransformation &Trans,
3174                                   DenseMatrix &I) const
3175    { LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
3176    using FiniteElement::Project;
Project(VectorCoefficient & vc,ElementTransformation & Trans,Vector & dofs) const3177    virtual void Project(VectorCoefficient &vc,
3178                         ElementTransformation &Trans, Vector &dofs) const
3179    {
3180       if (obasis1d.IsIntegratedType()) { ProjectIntegrated(vc, Trans, dofs); }
3181       else { Project_ND(tk, dof2tk, vc, Trans, dofs); }
3182    }
ProjectFromNodes(Vector & vc,ElementTransformation & Trans,Vector & dofs) const3183    virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
3184                                  Vector &dofs) const
3185    { Project_ND(tk, dof2tk, vc, Trans, dofs); }
ProjectMatrixCoefficient(MatrixCoefficient & mc,ElementTransformation & T,Vector & dofs) const3186    virtual void ProjectMatrixCoefficient(
3187       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
3188    { ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
Project(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3189    virtual void Project(const FiniteElement &fe,
3190                         ElementTransformation &Trans,
3191                         DenseMatrix &I) const
3192    { Project_ND(tk, dof2tk, fe, Trans, I); }
ProjectGrad(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & grad) const3193    virtual void ProjectGrad(const FiniteElement &fe,
3194                             ElementTransformation &Trans,
3195                             DenseMatrix &grad) const
3196    { ProjectGrad_ND(tk, dof2tk, fe, Trans, grad); }
3197 
3198 protected:
3199    void ProjectIntegrated(VectorCoefficient &vc,
3200                           ElementTransformation &Trans,
3201                           Vector &dofs) const;
3202 };
3203 
3204 
3205 /// Arbitrary order Nedelec elements in 3D on a tetrahedron
3206 class ND_TetrahedronElement : public VectorFiniteElement
3207 {
3208    static const double tk[18], c;
3209 
3210 #ifndef MFEM_THREAD_SAFE
3211    mutable Vector shape_x, shape_y, shape_z, shape_l;
3212    mutable Vector dshape_x, dshape_y, dshape_z, dshape_l;
3213    mutable DenseMatrix u;
3214 #endif
3215    Array<int> dof2tk;
3216    DenseMatrixInverse Ti;
3217 
3218 public:
3219    /// Construct the ND_TetrahedronElement of order @a p
3220    ND_TetrahedronElement(const int p);
3221    virtual void CalcVShape(const IntegrationPoint &ip,
3222                            DenseMatrix &shape) const;
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const3223    virtual void CalcVShape(ElementTransformation &Trans,
3224                            DenseMatrix &shape) const
3225    { CalcVShape_ND(Trans, shape); }
3226    virtual void CalcCurlShape(const IntegrationPoint &ip,
3227                               DenseMatrix &curl_shape) const;
GetLocalInterpolation(ElementTransformation & Trans,DenseMatrix & I) const3228    virtual void GetLocalInterpolation(ElementTransformation &Trans,
3229                                       DenseMatrix &I) const
3230    { LocalInterpolation_ND(*this, tk, dof2tk, Trans, I); }
GetLocalRestriction(ElementTransformation & Trans,DenseMatrix & R) const3231    virtual void GetLocalRestriction(ElementTransformation &Trans,
3232                                     DenseMatrix &R) const
3233    { LocalRestriction_ND(tk, dof2tk, Trans, R); }
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3234    virtual void GetTransferMatrix(const FiniteElement &fe,
3235                                   ElementTransformation &Trans,
3236                                   DenseMatrix &I) const
3237    { LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
3238    using FiniteElement::Project;
Project(VectorCoefficient & vc,ElementTransformation & Trans,Vector & dofs) const3239    virtual void Project(VectorCoefficient &vc,
3240                         ElementTransformation &Trans, Vector &dofs) const
3241    { Project_ND(tk, dof2tk, vc, Trans, dofs); }
ProjectFromNodes(Vector & vc,ElementTransformation & Trans,Vector & dofs) const3242    virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
3243                                  Vector &dofs) const
3244    { Project_ND(tk, dof2tk, vc, Trans, dofs); }
ProjectMatrixCoefficient(MatrixCoefficient & mc,ElementTransformation & T,Vector & dofs) const3245    virtual void ProjectMatrixCoefficient(
3246       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
3247    { ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
Project(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3248    virtual void Project(const FiniteElement &fe,
3249                         ElementTransformation &Trans,
3250                         DenseMatrix &I) const
3251    { Project_ND(tk, dof2tk, fe, Trans, I); }
ProjectGrad(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & grad) const3252    virtual void ProjectGrad(const FiniteElement &fe,
3253                             ElementTransformation &Trans,
3254                             DenseMatrix &grad) const
3255    { ProjectGrad_ND(tk, dof2tk, fe, Trans, grad); }
3256 
ProjectCurl(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & curl) const3257    virtual void ProjectCurl(const FiniteElement &fe,
3258                             ElementTransformation &Trans,
3259                             DenseMatrix &curl) const
3260    { ProjectCurl_ND(tk, dof2tk, fe, Trans, curl); }
3261 };
3262 
3263 /// Arbitrary order Nedelec elements in 2D on a triangle
3264 class ND_TriangleElement : public VectorFiniteElement
3265 {
3266    static const double tk[8], c;
3267 
3268 #ifndef MFEM_THREAD_SAFE
3269    mutable Vector shape_x, shape_y, shape_l;
3270    mutable Vector dshape_x, dshape_y, dshape_l;
3271    mutable DenseMatrix u;
3272    mutable Vector curlu;
3273 #endif
3274    Array<int> dof2tk;
3275    DenseMatrixInverse Ti;
3276 
3277 public:
3278    /// Construct the ND_TriangleElement of order @a p
3279    ND_TriangleElement(const int p);
3280    virtual void CalcVShape(const IntegrationPoint &ip,
3281                            DenseMatrix &shape) const;
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const3282    virtual void CalcVShape(ElementTransformation &Trans,
3283                            DenseMatrix &shape) const
3284    { CalcVShape_ND(Trans, shape); }
3285    virtual void CalcCurlShape(const IntegrationPoint &ip,
3286                               DenseMatrix &curl_shape) const;
GetLocalInterpolation(ElementTransformation & Trans,DenseMatrix & I) const3287    virtual void GetLocalInterpolation(ElementTransformation &Trans,
3288                                       DenseMatrix &I) const
3289    { LocalInterpolation_ND(*this, tk, dof2tk, Trans, I); }
GetLocalRestriction(ElementTransformation & Trans,DenseMatrix & R) const3290    virtual void GetLocalRestriction(ElementTransformation &Trans,
3291                                     DenseMatrix &R) const
3292    { LocalRestriction_ND(tk, dof2tk, Trans, R); }
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3293    virtual void GetTransferMatrix(const FiniteElement &fe,
3294                                   ElementTransformation &Trans,
3295                                   DenseMatrix &I) const
3296    { LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
3297    using FiniteElement::Project;
Project(VectorCoefficient & vc,ElementTransformation & Trans,Vector & dofs) const3298    virtual void Project(VectorCoefficient &vc,
3299                         ElementTransformation &Trans, Vector &dofs) const
3300    { Project_ND(tk, dof2tk, vc, Trans, dofs); }
ProjectFromNodes(Vector & vc,ElementTransformation & Trans,Vector & dofs) const3301    virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
3302                                  Vector &dofs) const
3303    { Project_ND(tk, dof2tk, vc, Trans, dofs); }
ProjectMatrixCoefficient(MatrixCoefficient & mc,ElementTransformation & T,Vector & dofs) const3304    virtual void ProjectMatrixCoefficient(
3305       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
3306    { ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
Project(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3307    virtual void Project(const FiniteElement &fe,
3308                         ElementTransformation &Trans,
3309                         DenseMatrix &I) const
3310    { Project_ND(tk, dof2tk, fe, Trans, I); }
ProjectGrad(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & grad) const3311    virtual void ProjectGrad(const FiniteElement &fe,
3312                             ElementTransformation &Trans,
3313                             DenseMatrix &grad) const
3314    { ProjectGrad_ND(tk, dof2tk, fe, Trans, grad); }
3315 };
3316 
3317 
3318 /// Arbitrary order Nedelec elements in 1D on a segment
3319 class ND_SegmentElement : public VectorTensorFiniteElement
3320 {
3321    static const double tk[1];
3322    Array<int> dof2tk;
3323 
3324 public:
3325    /** @brief Construct the ND_SegmentElement of order @a p and open
3326        BasisType @a ob_type */
3327    ND_SegmentElement(const int p, const int ob_type = BasisType::GaussLegendre);
CalcShape(const IntegrationPoint & ip,Vector & shape) const3328    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const
3329    { obasis1d.Eval(ip.x, shape); }
3330    virtual void CalcVShape(const IntegrationPoint &ip,
3331                            DenseMatrix &shape) const;
CalcVShape(ElementTransformation & Trans,DenseMatrix & shape) const3332    virtual void CalcVShape(ElementTransformation &Trans,
3333                            DenseMatrix &shape) const
3334    { CalcVShape_ND(Trans, shape); }
3335    // virtual void CalcCurlShape(const IntegrationPoint &ip,
3336    //                            DenseMatrix &curl_shape) const;
GetLocalInterpolation(ElementTransformation & Trans,DenseMatrix & I) const3337    virtual void GetLocalInterpolation(ElementTransformation &Trans,
3338                                       DenseMatrix &I) const
3339    { LocalInterpolation_ND(*this, tk, dof2tk, Trans, I); }
GetLocalRestriction(ElementTransformation & Trans,DenseMatrix & R) const3340    virtual void GetLocalRestriction(ElementTransformation &Trans,
3341                                     DenseMatrix &R) const
3342    { LocalRestriction_ND(tk, dof2tk, Trans, R); }
GetTransferMatrix(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3343    virtual void GetTransferMatrix(const FiniteElement &fe,
3344                                   ElementTransformation &Trans,
3345                                   DenseMatrix &I) const
3346    { LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
3347    using FiniteElement::Project;
Project(VectorCoefficient & vc,ElementTransformation & Trans,Vector & dofs) const3348    virtual void Project(VectorCoefficient &vc,
3349                         ElementTransformation &Trans, Vector &dofs) const
3350    { Project_ND(tk, dof2tk, vc, Trans, dofs); }
ProjectMatrixCoefficient(MatrixCoefficient & mc,ElementTransformation & T,Vector & dofs) const3351    virtual void ProjectMatrixCoefficient(
3352       MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
3353    { ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
Project(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & I) const3354    virtual void Project(const FiniteElement &fe,
3355                         ElementTransformation &Trans,
3356                         DenseMatrix &I) const
3357    { Project_ND(tk, dof2tk, fe, Trans, I); }
ProjectGrad(const FiniteElement & fe,ElementTransformation & Trans,DenseMatrix & grad) const3358    virtual void ProjectGrad(const FiniteElement &fe,
3359                             ElementTransformation &Trans,
3360                             DenseMatrix &grad) const
3361    { ProjectGrad_ND(tk, dof2tk, fe, Trans, grad); }
3362 };
3363 
3364 
3365 /// An arbitrary order and dimension NURBS element
3366 class NURBSFiniteElement : public ScalarFiniteElement
3367 {
3368 protected:
3369    mutable Array <const KnotVector*> kv;
3370    mutable const int *ijk;
3371    mutable int patch, elem;
3372    mutable Vector weights;
3373 
3374 public:
3375    /** @brief Construct NURBSFiniteElement with given
3376        @param D    Reference space dimension
3377        @param G    Geometry type (of type Geometry::Type)
3378        @param Do   Number of degrees of freedom in the FiniteElement
3379        @param O    Order/degree of the FiniteElement
3380        @param F    FunctionSpace type of the FiniteElement
3381     */
NURBSFiniteElement(int D,Geometry::Type G,int Do,int O,int F)3382    NURBSFiniteElement(int D, Geometry::Type G, int Do, int O, int F)
3383       : ScalarFiniteElement(D, G, Do, O, F)
3384    {
3385       ijk = NULL;
3386       patch = elem = -1;
3387       kv.SetSize(dim);
3388       weights.SetSize(dof);
3389       weights = 1.0;
3390    }
3391 
Reset() const3392    void                 Reset      ()         const { patch = elem = -1; }
SetIJK(const int * IJK) const3393    void                 SetIJK     (const int *IJK) const { ijk = IJK; }
GetPatch() const3394    int                  GetPatch   ()         const { return patch; }
SetPatch(int p) const3395    void                 SetPatch   (int p)    const { patch = p; }
GetElement() const3396    int                  GetElement ()         const { return elem; }
SetElement(int e) const3397    void                 SetElement (int e)    const { elem = e; }
KnotVectors() const3398    Array <const KnotVector*> &KnotVectors()   const { return kv; }
Weights() const3399    Vector              &Weights    ()         const { return weights; }
3400    /// Update the NURBSFiniteElement according to the currently set knot vectors
SetOrder() const3401    virtual void         SetOrder   ()         const { }
3402 };
3403 
3404 
3405 /// An arbitrary order 1D NURBS element on a segment
3406 class NURBS1DFiniteElement : public NURBSFiniteElement
3407 {
3408 protected:
3409    mutable Vector shape_x;
3410 
3411 public:
3412    /// Construct the NURBS1DFiniteElement of order @a p
NURBS1DFiniteElement(int p)3413    NURBS1DFiniteElement(int p)
3414       : NURBSFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk),
3415         shape_x(p + 1) { }
3416 
3417    virtual void SetOrder() const;
3418    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
3419    virtual void CalcDShape(const IntegrationPoint &ip,
3420                            DenseMatrix &dshape) const;
3421    virtual void CalcHessian (const IntegrationPoint &ip,
3422                              DenseMatrix &hessian) const;
3423 };
3424 
3425 /// An arbitrary order 2D NURBS element on a square
3426 class NURBS2DFiniteElement : public NURBSFiniteElement
3427 {
3428 protected:
3429    mutable Vector u, shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
3430    mutable DenseMatrix du;
3431 
3432 public:
3433    /// Construct the NURBS2DFiniteElement of order @a p
NURBS2DFiniteElement(int p)3434    NURBS2DFiniteElement(int p)
3435       : NURBSFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p,
3436                            FunctionSpace::Qk),
3437         u(dof), shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
3438         dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1), du(dof,2)
3439    { orders[0] = orders[1] = p; }
3440 
3441    /// Construct the NURBS2DFiniteElement with x-order @a px and y-order @a py
NURBS2DFiniteElement(int px,int py)3442    NURBS2DFiniteElement(int px, int py)
3443       : NURBSFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1),
3444                            std::max(px, py), FunctionSpace::Qk),
3445         u(dof), shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
3446         dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1), du(dof,2)
3447    { orders[0] = px; orders[1] = py; }
3448 
3449    virtual void SetOrder() const;
3450    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
3451    virtual void CalcDShape(const IntegrationPoint &ip,
3452                            DenseMatrix &dshape) const;
3453    virtual void CalcHessian (const IntegrationPoint &ip,
3454                              DenseMatrix &hessian) const;
3455 };
3456 
3457 /// An arbitrary order 3D NURBS element on a cube
3458 class NURBS3DFiniteElement : public NURBSFiniteElement
3459 {
3460 protected:
3461    mutable Vector u, shape_x, shape_y, shape_z;
3462    mutable Vector dshape_x, dshape_y, dshape_z;
3463    mutable Vector d2shape_x, d2shape_y, d2shape_z;
3464    mutable DenseMatrix du;
3465 
3466 public:
3467    /// Construct the NURBS3DFiniteElement of order @a p
NURBS3DFiniteElement(int p)3468    NURBS3DFiniteElement(int p)
3469       : NURBSFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p,
3470                            FunctionSpace::Qk),
3471         u(dof), shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
3472         dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
3473         d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1), du(dof,3)
3474    { orders[0] = orders[1] = orders[2] = p; }
3475 
3476    /// Construct the NURBS3DFiniteElement with x-order @a px and y-order @a py
3477    /// and z-order @a pz
NURBS3DFiniteElement(int px,int py,int pz)3478    NURBS3DFiniteElement(int px, int py, int pz)
3479       : NURBSFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1),
3480                            std::max(std::max(px,py),pz), FunctionSpace::Qk),
3481         u(dof), shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
3482         dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
3483         d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1), du(dof,3)
3484    { orders[0] = px; orders[1] = py; orders[2] = pz; }
3485 
3486    virtual void SetOrder() const;
3487    virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
3488    virtual void CalcDShape(const IntegrationPoint &ip,
3489                            DenseMatrix &dshape) const;
3490    virtual void CalcHessian (const IntegrationPoint &ip,
3491                              DenseMatrix &hessian) const;
3492 };
3493 
3494 } // namespace mfem
3495 
3496 #endif
3497