LifeV
FESpace.hpp
Go to the documentation of this file.
1 //@HEADER
2 /*
3 *******************************************************************************
4 
5  Copyright (C) 2004, 2005, 2007 EPFL, Politecnico di Milano, INRIA
6  Copyright (C) 2010 EPFL, Politecnico di Milano, Emory University
7 
8  This file is part of LifeV.
9 
10  LifeV is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  LifeV is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with LifeV. If not, see <http://www.gnu.org/licenses/>.
22 
23 *******************************************************************************
24 */
25 //@HEADER
26 
27 /*!
28  @file
29  @brief This files contains the description and the implementation of the FESpace class.
30 
31  @author Gilles Fourestey <gilles.fourestey@epfl.ch>
32  @date 00-06-2007
33 
34  @contributor Samuel Quinodoz <samuel.quinodoz@epfl.ch>
35  @contributor Mauro Perego <mperego@fsu.edu>
36  @mantainer Samuel Quinodoz <samuel.quinodoz@epfl.ch>
37 
38  */
39 
40 
41 
42 
43 #ifndef _FESPACE_H_
44 #define _FESPACE_H_
45 
46 #include <iomanip>
47 #include <sstream>
48 #include <utility>
49 
50 #include <lifev/core/LifeV.hpp>
51 
52 #include <lifev/core/fem/BCHandler.hpp>
53 #include <lifev/core/fem/CurrentFE.hpp>
54 #include <lifev/core/fem/CurrentFEManifold.hpp>
55 #include <lifev/core/fem/DOF.hpp>
56 #include <lifev/core/fem/SobolevNorms.hpp>
57 
58 #include <lifev/core/mesh/MeshPartitioner.hpp>
59 
60 
61 namespace LifeV
62 {
63 
64 template < typename MeshType, typename MapType, typename ReturnType >
65 class FEFunction;
66 
67 
68 
69 //! FESpace - Short description here please!
70 /*!
71  * @author Gilles Fourestey
72  *
73  * Class representing the FE space, i.e. the reference FE and the geometric mapping.
74  *
75  */
76 
77 template <typename MeshType, typename MapType>
78 class FESpace
79 {
80 
81 public:
82 
83  //! @name Public Types
84  //@{
85 
86  typedef std::function < Real ( Real const&, Real const&, Real const&,
87  Real const&, ID const& ) > function_Type;
88  typedef MeshType mesh_Type;
89  typedef std::shared_ptr<mesh_Type> meshPtr_Type;
90  typedef MapType map_Type;
91  typedef std::shared_ptr<map_Type> mapPtr_Type;
92  typedef typename map_Type::commPtr_Type commPtr_Type;
93 
94  //@}
95 
96 
97  //! @name Constructor & Destructor
98  //@{
99 
100  /*!
101  \param data_file GetPot data file
102  \param refFE_u reference FE for the velocity
103  \param refFE_p reference FE for the pressure
104  \param Qr_u element quadrature rule for the velocity
105  \param bdQr_u surface quadrature rule for the velocity
106  \param Qr_p element quadrature rule for the pressure
107  \param bdQr_p surface quadrature rule for the pressure
108  \param BCh_fluid boundary conditions for the fluid
109  \param ord_bdf order of the bdf time advancing scheme and incremental pressure approach (default: Backward Euler)
110  */
111 
112  LIFEV_DEPRECATED ( FESpace ( MeshPartitioner<MeshType>& mesh,
113  const ReferenceFE& refFE,
114  const QuadratureRule& Qr,
115  const QuadratureRule& bdQr,
116  const Int fDim,
117  const commPtr_Type& commptr
118  ) );
119 
120  LIFEV_DEPRECATED ( FESpace ( MeshPartitioner<MeshType>& mesh,
121  const std::string& space,
122  const Int fDim,
123  const commPtr_Type& commptr
124  ) );
125 
126  FESpace ( meshPtr_Type mesh,
127  const ReferenceFE& refFE,
128  const QuadratureRule& Qr,
129  const QuadratureRule& bdQr,
130  const Int fDim,
131  const commPtr_Type& commptr
132  );
133 
134  FESpace ( meshPtr_Type mesh,
135  const std::string& space,
136  const Int fDim,
137  const commPtr_Type& commptr
138  );
139 
140  //! Do nothing destructor
141  virtual ~FESpace() {}
142 
143  //@}
144 
145 
146  //! @name Methods
147  //@{
148 
149  //! Interpolate a given function nodally onto a vector
150  template<typename vector_type>
151  void interpolate ( const function_Type& fct, vector_type& vect, const Real time = 0.);
152 
153  template<typename vector_type>
154  void interpolateBC ( BCHandler& BCh, vector_type& vect, const Real time);
155 
156  //! Interpolation method for FEFunctions
157  /*!
158  @param fEFunction Pointer to an FEFunction
159  @param vector Interpolated function
160  @param time Time in the interpolation
161  */
162  template < typename ReturnType, typename vector_type >
163  void interpolate ( const FEFunction<MeshType, MapType, ReturnType>* fEFunction,
164  vector_type& vector, const Real time = 0. );
165 
166  //! calculate L2 velocity error for given exact velocity function
167  //! \param pexact the exact velocity as a function
168  //! \param time the time
169  //! \param relError Real* to store the relative error in
170 
171  // this computes vec = \int fct phi_i
172  template<typename vector_type>
173  void l2ScalarProduct ( const function_Type& fct,
174  vector_type& vec,
175  const Real t );
176 
177  template<typename vector_type>
178  Real l20Error ( const function_Type& fexact,
179  const vector_type& vec,
180  const Real time,
181  Real* relError = 0 );
182 
183  template<typename vector_type>
184  Real l2Error ( const function_Type& fexact,
185  const vector_type& vec,
186  const Real time,
187  Real* relError = 0 );
188 
189  template<typename function, typename vector_type>
190  Real h1Error ( const function& fexact,
191  const vector_type& vec,
192  const Real time,
193  Real* relError = 0 );
194 
195 
196  template<typename vector_type>
197  Real l2Norm ( const vector_type& vec );
198 
199  template<typename function>
200  Real l2NormFunction ( const function& f, const Real time = 0);
201 
202  template<typename vector_type>
203  Real h1Norm ( const vector_type& vec );
204 
205 
206  //! Method to computes the L2 error when using a weight function
207  /*!
208  The scope of this method is to compute \f$ \left( \int w (u_{exact} - u_h) \right)^{1/2} \f$.
209  The usual L2 error norm can be retrieved by using \f$ w=1 \f$
210  */
211  template<typename vector_type>
212  Real l2ErrorWeighted ( const function_Type& exactSolution,
213  const vector_type& solution,
214  const function_Type& weight,
215  const Real time);
216 
217 
218  //! This method computes the interpolate value of a given FE function in a given point.
219  /*!
220  * The user of this function has to provide the element and the vector of the DOF values.
221  * Given these informations and a point P, the function compute the value:
222  * value = sum_{dof i} v(i) phi_i(P)
223  *
224  * Note that the point P can be outside of the element considered (this is NOT checked).
225  *
226  * Warning: this method has been only checked in 3D.
227  *
228  * @param elementID The ID of the element considered. The ID is the local ID
229  * (not the global one, see in the MeshEntity class).
230  * @param solutionVector The vector containing the values in all nodes (not only of
231  * the considered element).
232  * @param pt The point where to perform the interpolation. Note that pt must allow
233  * for STL-type accessor [] and must have the size() method (typically a std::vector<Real>).
234  * @param component The component for which the interpolation has to be performed
235  * (usefull only for the vectorial FE, set to 0 if the FE is scalar).
236  * @return The interpolated value in the point.
237  * @author Samuel Quinodoz
238  * @date 13-01-2010
239  */
240 
241  template<typename point_type, typename vector_type>
242  Real feInterpolateValue (const ID& elementID, const vector_type& solutionVector,
243  const point_type& pt, const UInt& component = 0) const;
244 
245 
246  //! This method computes the interpolate value of a given FE function in a given point.
247  /*!
248  * This method is the same as feInterpolateValue, but for the definition of the solution
249  * vector. Here, the solution is given only for the degrees of freedom of the given
250  * element. The parameter solutionVector is typically a std::vector<Real> containing
251  * the values in the dofs.
252  *
253  * It is not possible to specify the component, the user has to provide directly the
254  * values for the wanted component in the solutionVector.
255  *
256  * @author Samuel Quinodoz
257  * @date 13-01-2010
258  */
259 
260  template<typename point_type, typename vector_type>
261  Real feInterpolateValueLocal (const ID& elementID, const vector_type& solutionVector,
262  const point_type& pt ) const;
263 
264 
265  //! This method computes the interpolated gradient of a given FE function in a given point.
266  /*!
267  * This method is the same as feInterpolateValue, but it computes the gradient insted of
268  * the value. Therefor, the desired element of the gradient has to be expressed using the
269  * parameter gradientElement.
270  *
271  * For example, if gradientElement=i and component=j, then the results corresponds to the
272  * value of partial u_j / partial x_i.
273  *
274  * Warning: This method has not been tested deeply, buggy behaviour is possible.
275  *
276  * @author Samuel Quinodoz
277  * @date 13-01-2010
278  */
279 
280  template<typename point_type, typename vector_type>
281  Real feInterpolateGradient (const ID& elementID, const vector_type& solutionVector, const point_type& pt,
282  const UInt& gradientElement, const UInt& component = 0 ) const;
283 
284 
285  //! This method computes the interpolated gradient of a given FE function in a given point.
286  /*!
287  * This method is the same as feInterpolateGradient, but it works with local values only,
288  * just as feInterpolateValueLocal.
289  *
290  * Warning: This method has not been tested deeply, buggy behaviour is possible.
291  *
292  * @author Samuel Quinodoz
293  * @date 13-01-2010
294  */
295 
296  template<typename point_type, typename vector_type>
297  Real feInterpolateGradientLocal (const ID& elementID, const vector_type& solutionVector, const point_type& pt,
298  const UInt& gradientElement ) const;
299 
300 
301  //! This method enables to pass a solution from one FESpace to the present one.
302  /*!
303  * This method interpolates the values of a FE solution (given by the vector and the FESpace)
304  * in the dofs of the present FESpace: we note \f$ v_i \f$ the component of the vector given in
305  * argument and \f$ phi_i \f$ the basis functions of the FESpace given in argument. This defines a
306  * function on the domain given by: \f$ f(x) = \sum_i v_i \phi_i(x) \f$.
307  *
308  * We search then the function \f$ g(x) \f$ belonging to the present FESpace such that \f$ g(x_j) = f(x_j) \f$
309  * for all \f$ x_j \f$ dofs of the present FESpace. This function returns the vector \f$ w_j \f$ such that
310  * \f$ g(x) = sum_j w_j psi_j(x) \f$ where \f$ psi_j \f$ are the basis functions of the present space.
311  *
312  * Warning: It is NOT true in general that \f$ w_j = f(x_j) \f$ (it is for lagrangian FEs). For
313  * example, if we want to pass the solution from the P_1 to the P_1 with bubbles, then
314  * the value associated to the bubble function will be always 0 even if the value of f
315  * is not 0 at the location of the dof of the bubble!
316  *
317  * @param originalSpace The space where the solution is defined originally.
318  * @param originalVector The vector of the solution in the original space.
319  * @param outputMapType The map type (default: Unique) of the the returned vector.
320  * @return The vector in the current FESpace having map type outputMapType.
321  * @author Samuel Quinodoz
322  * @date 13-01-2010
323  */
324 
325  template <typename vector_type>
326  vector_type feToFEInterpolate (const FESpace<mesh_Type, map_Type>& originalSpace,
327  const vector_type& originalVector, const MapEpetraType& outputMapType = Unique) const;
328 
329  //! This method reconstruct a gradient of a solution in the present FE space.
330  /*!
331  The goal of this method is to build an approximation of the gradient of a given
332  FE function in this FESpace. Typically, when one use P1 elements for approximating
333  the solution of a given problem, the gradient is only piecewise constant. However, one
334  could need continuous gradient. The solutions to this problem is either to use specific
335  finite elements (like Hermite FE) or rely on a recovery procedure for the gradient.
336 
337  This method implements a recovery procedure that performs a local average with weights
338  corresponding to the areas of the elements:
339  \f[ Gr(P) = \frac{\sum_{P \in T} |T| \nabla u(P)}{\sum_{P \in T} |T|} \f]
340  See Zienkiewicz and Zhu (1987) for more details.
341 
342  @Note Results might be very wrong if you are not using lagrangian FE for tetrahedra
343  */
344  template <typename vector_type>
345  vector_type gradientRecovery (const vector_type& solution, const UInt& component) const;
346 
347  //! This method reconstruct a gradient of a solution in the present FE space.
348  /*!
349  The goal of this method is to build an approximation of the gradient of a given
350  FE function in this FESpace. Typically, when one use P1 elements for approximating
351  the solution of a given problem, the gradient is only piecewise constant. However, one
352  could need continuous gradient. The solutions to this problem is either to use specific
353  finite elements (like Hermite FE) or rely on a recovery procedure for the gradient.
354 
355  This method implements a recovery procedure that performs a local average with weights
356  corresponding to the areas of the elements:
357  \f[ Gr(P) = \frac{\sum_{P \in T} |T| \nabla u(P)}{\sum_{P \in T} |T|} \f]
358  See Zienkiewicz and Zhu (1987) for more details.
359 
360  @Note Results might be very wrong if you are not using lagrangian FE for tetrahedra
361  */
362  template <typename vector_type>
363  vector_type recoveryFunction (const vector_type& solution) const;
364 
365  //! Reconstruction of the laplacian using gradientRecovery procedures.
366  /*!
367  This method simply uses the FESpace::gradientRecovery method several times so
368  that one can get a continuous approximation of the laplacian of the given solution.
369 
370  @Note Results might be very wrong if you are not using lagrangian FE for tetrahedra
371  */
372  template <typename vector_type>
373  vector_type laplacianRecovery (const vector_type& solution) const;
374 
375  //! Return the polynomial degree of the finite element used
376  UInt polynomialDegree() const;
377 
378  //@}
379 
380  //! @name Set Methods
381  //@{
382 
383  //! Method to set replace the quadrule
384  /*!
385  @param Qr The new quadrule to be used in the FESpace
386  */
387  void setQuadRule (const QuadratureRule& Qr);
388 
389  void setBdQuadRule (const QuadratureRule& bdQr);
390 
391  //@}
392 
393 
394  //! @name Get Methods
395  //@{
396 
397  // const mesh_type& mesh() {return M_mesh;}
398  // const mesh_type& mesh() const {return *M_mesh;}
399  // mesh_type& mesh() {return *M_mesh;}
400 
401  const meshPtr_Type& mesh() const
402  {
403  return M_mesh;
404  }
405  meshPtr_Type& mesh()
406  {
407  return M_mesh;
408  }
409 
410  //! Returns map
411  const map_Type& map() const
412  {
413  return *M_map;
414  }
415  map_Type& map()
416  {
417  return *M_map;
418  }
419 
420  const mapPtr_Type& mapPtr() const
421  {
422  return M_map;
423  }
424 
425  //! Returns the velocity dof
426  const DOF& dof() const
427  {
428  return *M_dof;
429  }
430  DOF& dof()
431  {
432  return *M_dof;
433  }
434  const std::shared_ptr<DOF>& dofPtr() const
435  {
436  return M_dof;
437  }
438 
439  //! Returns the current FE
440  const CurrentFE& fe() const
441  {
442  return *M_fe;
443  }
444  CurrentFE& fe()
445  {
446  return *M_fe;
447  }
448 
449  //! Returns the current boundary FE
451  {
452  return *M_feBd;
453  }
454 
455  //! Returns the res FE
456  const ReferenceFE& refFE() const
457  {
458  return *M_refFE;
459  }
460 
461  //! Returns the volumic quadratic rule
462  const QuadratureRule& qr() const
463  {
464  return *M_Qr;
465  }
466 
467  //! Returns the surfasic quadratic rule
468  const QuadratureRule& bdQr() const
469  {
470  return *M_bdQr;
471  }
472 
473  //! Returns FE space dimension
474  const UInt& dim() const
475  {
476  return M_dim;
477  }
478  const UInt& fieldDim() const
479  {
480  return M_fieldDim;
481  }
482 
483  //@}
484 
485 protected:
486 
487  //! @name Private Methods
488  //@{
489 
490  //! copy constructor
491  FESpace ( const FESpace& fespace );
492 
493  //! Creates the map for interprocessor communication
494  void createMap (const commPtr_Type& commptr);
495 
496  //! Resets boundary data if necessary
497  void resetBoundaryFE();
498 
499  //! Set space
500  inline void setSpace ( const std::string& space, UInt dimension );
501 
502 
503  //! This is a generic function called by feToFEInterpolate method.
504  //! It allows to interpolate vectors between any two continuous and scalar FE spaces. It is used when other specialized functions are not provided
505  /*!
506  * @param originalSpace The space where the solution is defined originally.
507  * @param originalVector The vector of the solution in the original space (must be a Repeated vector).
508  * @return The Repeated vector in the current FESpace.
509  * @author Mauro Perego
510  * @date 27-06-2011
511  */
512  template<typename vector_type>
513  vector_type interpolateGeneric ( const FESpace<mesh_Type, map_Type>& OriginalSpace,
514  const vector_type& OriginalVector) const;
515 
516  //! This is a specialized function called by feToFEInterpolate method.
517  //! It allows to interpolate P1bubble, P2 vectors into P1 vectors, P1 into P1bubble vectors and Q2 vectors into Q1 vectors.
518  /*!
519  * @param originalSpace The space where the solution is defined originally.
520  * @param originalVector The vector of the solution in the original space.
521  * @return The Unique vector in the current FESpace.
522  *
523  * @author Mauro Perego
524  * @date 27-06-2011
525  */
526 
527  template<typename vector_type>
528  vector_type linearInterpolate (const FESpace<mesh_Type, map_Type>& originalSpace,
529  const vector_type& originalVector) const;
530 
531  //! This is a specialized function called by feToFEInterpolate method.
532  //! It allows to interpolate P1, P1bubble vectors into P2 vectors, and Q1 vectors into Q2 vectors.
533  /*!
534  * @param originalSpace The space where the solution is defined originally.
535  * @param originalVector The vector of the solution in the original space (must be a Repeated vector).
536  * @return The Repeated vector in the current FESpace.
537  * @author Samuel Quinodoz
538  * @date 13-01-2010
539  */
540  template<typename vector_type>
541  vector_type P2Interpolate (const FESpace<mesh_Type, map_Type>& original_space,
542  const vector_type& original_vector) const;
543 
544 
545  //! This is a specialized function called by FESpace::feToFEInterpolate method for RT0 to P0 interpolation
546  /*!
547  * @author Alessio Fumagalli
548  * @date 13-01-2010
549  */
550  template<typename vector_type>
551  vector_type RT0ToP0Interpolate (const FESpace<mesh_Type, map_Type>& original_space,
552  const vector_type& original_vector) const;
553  //@}
554 
555 
556 
557 
558  //! Set space Map (useful for switch syntax with strings)
559  enum spaceData {P0 = 1, P1 = 10, P1_HIGH = 15, P1Bubble = 16, P2 = 20, P2_HIGH = 25, P2Bubble = 26};
560  std::map<std::string, spaceData> M_spaceMap;
561 
562  //! reference to the mesh
563  meshPtr_Type M_mesh;
564 
565  //! Reference FE for the velocity
566  const ReferenceFE* M_refFE;
567 
568  //! Quadrature rule for volumic elementary computations
569  const QuadratureRule* M_Qr;
570 
571  //! Quadrature rule for surface elementary computations
572  const QuadratureRule* M_bdQr;
573 
574  //! dimension of the field variable ( scalar/vector field)
575  UInt M_fieldDim;
576 
577  //! A shared pointer to the DOF object
578  std::shared_ptr<DOF> M_dof;
579 
580  //! The number of total dofs
581  UInt M_dim;
582 
583  //! Current FE
584  std::shared_ptr<CurrentFE> M_fe;
585  std::shared_ptr<CurrentFEManifold> M_feBd;
586 
587  //! Map
588  mapPtr_Type M_map;
589 
590 };
591 
592 // ===================================================
593 // Constructors & Destructor
594 // ===================================================
595 
596 template <typename MeshType, typename MapType>
597 FESpace<MeshType, MapType>::
598 FESpace ( MeshPartitioner<MeshType>& mesh,
599  const ReferenceFE& refFE,
600  const QuadratureRule& Qr,
601  const QuadratureRule& bdQr,
602  const Int fDim,
603  const commPtr_Type& commptr
604  ) :
605  M_mesh ( mesh.meshPartition() ),
606  M_refFE ( &refFE ),
607  M_Qr ( &Qr ),
608  M_bdQr ( &bdQr ),
609  M_fieldDim ( fDim ),
610  M_dof ( new DOF ( *M_mesh, *M_refFE ) ),
611  M_dim ( M_dof->numTotalDof() ),
612  M_fe ( new CurrentFE ( *M_refFE, getGeometricMap ( *M_mesh ), *M_Qr ) ),
613  M_feBd ( ),
614  M_map ( new map_Type() )
615 {
616  resetBoundaryFE();
617  createMap (commptr);
618 }
619 
620 template <typename MeshType, typename MapType>
621 FESpace<MeshType, MapType>::
622 FESpace ( MeshPartitioner<MeshType>& mesh,
623  const std::string& space,
624  const Int fDim,
625  const commPtr_Type& commptr
626  ) :
627  M_mesh ( mesh.meshPartition() ),
628  M_fieldDim ( fDim ),
629  M_dof ( ),
630  M_fe ( ),
631  M_feBd ( ),
632  M_map ( new map_Type() )
633 {
634  // Set spaceMap
635  M_spaceMap["P0"] = P0;
636  M_spaceMap["P1"] = P1;
637  M_spaceMap["P1_HIGH"] = P1_HIGH;
638  M_spaceMap["P1Bubble"] = P1Bubble;
639  M_spaceMap["P2"] = P2;
640  M_spaceMap["P2_HIGH"] = P2_HIGH;
641  M_spaceMap["P2Bubble"] = P2Bubble;
642 
643  // Set space
644  setSpace ( space, mesh_Type::S_geoDimensions );
645 
646  // Set other quantities
647  M_dof.reset ( new DOF ( *M_mesh, *M_refFE ) );
648  M_dim = M_dof->numTotalDof();
649  M_fe.reset ( new CurrentFE ( *M_refFE, getGeometricMap ( *M_mesh ), *M_Qr ) );
650  resetBoundaryFE();
651  createMap (commptr);
652 }
653 
654 template <typename MeshType, typename MapType>
655 FESpace<MeshType, MapType>::
656 FESpace ( meshPtr_Type mesh,
657  const ReferenceFE& refFE,
658  const QuadratureRule& Qr,
659  const QuadratureRule& bdQr,
660  const Int fDim,
661  const commPtr_Type& commptr
662  ) :
663  M_mesh ( mesh ),
664  M_refFE ( &refFE ),
665  M_Qr ( &Qr ),
666  M_bdQr ( &bdQr ),
667  M_fieldDim ( fDim ),
668  M_dof ( new DOF ( *M_mesh, *M_refFE ) ),
669  M_dim ( M_dof->numTotalDof() ),
670  M_fe ( new CurrentFE ( *M_refFE, getGeometricMap ( *M_mesh ), *M_Qr ) ),
671  M_feBd ( ),
672  M_map ( new map_Type() )
673 {
674  createMap (commptr);
675  resetBoundaryFE();
676 }
677 
678 template <typename MeshType, typename MapType>
679 FESpace<MeshType, MapType>::
680 FESpace ( meshPtr_Type mesh,
681  const std::string& space,
682  const Int fDim,
683  const commPtr_Type& commptr
684  ) :
685  M_mesh ( mesh ),
686  M_fieldDim ( fDim ),
687  M_dof ( ),
688  M_fe ( ),
689  M_feBd ( ),
690  M_map ( new map_Type() )
691 {
692  // Set spaceMap
693  M_spaceMap["P0"] = P0;
694  M_spaceMap["P1"] = P1;
695  M_spaceMap["P1_HIGH"] = P1_HIGH;
696  M_spaceMap["P1Bubble"] = P1Bubble;
697  M_spaceMap["P2"] = P2;
698  M_spaceMap["P2_HIGH"] = P2_HIGH;
699  M_spaceMap["P2Bubble"] = P2Bubble;
700 
701  // Set space
702  setSpace ( space, mesh_Type::S_geoDimensions );
703 
704  // Set other quantities
705  M_dof.reset ( new DOF ( *M_mesh, *M_refFE ) );
706  M_dim = M_dof->numTotalDof();
707  M_fe.reset ( new CurrentFE ( *M_refFE, getGeometricMap ( *M_mesh ), *M_Qr ) );
708  resetBoundaryFE();
709  createMap (commptr);
710 }
711 
712 // ===================================================
713 // Methods
714 // ===================================================
715 
716 
717 template <typename MeshType, typename MapType>
718 template<typename vector_type>
719 void
720 FESpace<MeshType, MapType>::interpolate ( const function_Type& fct,
721  vector_type& vect,
722  const Real time)
723 {
724  // First, we build a "quadrature" that consists in the nodes (0 weight)
725  QuadratureRule interpQuad;
726  interpQuad.setDimensionShape (shapeDimension (M_refFE->shape() ), M_refFE->shape() );
727  interpQuad.setPoints (M_refFE->refCoor(), std::vector<Real> (M_refFE->nbDof(), 0) );
728 
729  // Then, we define a currentFE with nodes on the reference nodes
730  CurrentFE interpCFE (*M_refFE, getGeometricMap (*M_mesh ), interpQuad);
731 
732  // Some constants
733  UInt totalNumberElements (M_mesh->numElements() );
734  UInt numberLocalDof (M_dof->numLocalDof() );
735 
736  // Storage for the values
737  std::vector<Real> nodalValues (numberLocalDof, 0);
738  std::vector<Real> FEValues (numberLocalDof, 0);
739 
740  // Do the loop over the cells
741  for (UInt iterElement (0); iterElement < totalNumberElements; ++iterElement)
742  {
743  // We update the CurrentFE so that we get the coordinates of the nodes
744  interpCFE.update (M_mesh->element (iterElement), UPDATE_QUAD_NODES);
745 
746  // Loop over the dimension of the field
747  for (UInt iDim (0); iDim < M_fieldDim; ++iDim)
748  {
749  // Loop over the degrees of freedom (= quadrature nodes)
750  for (UInt iterDof (0); iterDof < numberLocalDof; ++iterDof)
751  {
752  // Store the nodal value
753  nodalValues[iterDof] = fct (time, interpCFE.quadNode (iterDof, 0), interpCFE.quadNode (iterDof, 1)
754  , interpCFE.quadNode (iterDof, 2), iDim);
755  }
756 
757  // Transform the nodal values in FE values
758  FEValues = M_refFE->nodalToFEValues (nodalValues);
759 
760  // Then on the dimension of the FESpace (scalar field vs vectorial field)
761  for (UInt iterDof (0); iterDof < numberLocalDof; ++iterDof)
762  {
763  // Find the ID of the considered DOF
764  ID globalDofID (M_dof->localToGlobalMap (iterElement, iterDof) + iDim * M_dim);
765 
766  // Compute the value of the function and set it
767  vect.setCoefficient (globalDofID, FEValues[iterDof]);
768 
769  }
770  }
771  }
772 }
773 
774 template < typename MeshType, typename MapType>
775 template < typename ReturnType, typename vector_type>
776 void FESpace<MeshType, MapType>::
777 interpolate ( const FEFunction<MeshType, MapType, ReturnType>* fEFunction,
778  vector_type& vector, const Real time )
779 {
780 
781  // First, we build a "quadrature" that consists in the nodes (0 weight)
782  QuadratureRule interpQuad;
783  interpQuad.setDimensionShape ( shapeDimension (M_refFE->shape() ), M_refFE->shape() );
784  interpQuad.setPoints ( M_refFE->refCoor(), std::vector<Real> (M_refFE->nbDof(), 0) );
785 
786  // Then, we define a currentFE with nodes on the reference nodes
787  CurrentFE interpCFE ( *M_refFE, getGeometricMap ( *M_mesh ), interpQuad );
788 
789  // Some constants
790  const UInt totalNumberElements ( M_mesh->numElements() );
791  const UInt numberLocalDof ( M_dof->numLocalDof() );
792 
793  // Storage for the values
794  typename FEFunction<MeshType, MapType, ReturnType>::point_Type point;
795  std::vector<Real> nodalValues (numberLocalDof, 0);
796  std::vector<Real> FEValues (numberLocalDof, 0);
797 
798  // Do the loop over the cells
799  for (UInt iterElement (0); iterElement < totalNumberElements; ++iterElement)
800  {
801  // We update the CurrentFE so that we get the coordinates of the nodes
802  interpCFE.update ( M_mesh->element (iterElement), UPDATE_QUAD_NODES );
803 
804  // Loop over the dimension of the field
805  for (UInt iDim (0); iDim < M_fieldDim; ++iDim)
806  {
807  // Loop over the degrees of freedom (= quadrature nodes)
808  for (UInt iterDof (0); iterDof < numberLocalDof; ++iterDof)
809  {
810  point [0] = interpCFE.quadNode ( iterDof, 0 );
811  point [1] = interpCFE.quadNode ( iterDof, 1 );
812  point [2] = interpCFE.quadNode ( iterDof, 2 );
813  // Store the nodal value
814  nodalValues[iterDof] = fEFunction->eval ( iterElement, point, time );
815  }
816 
817  // Transform the nodal values in FE values
818  FEValues = M_refFE->nodalToFEValues ( nodalValues );
819 
820  // Then on the dimension of the FESpace (scalar field vs vectorial field)
821  for (UInt iterDof (0); iterDof < numberLocalDof; ++iterDof)
822  {
823  // Find the ID of the considered DOF
824  const ID globalDofID ( M_dof->localToGlobalMap ( iterElement, iterDof ) + iDim * M_dim );
825 
826  // Compute the value of the function and set it
827  vector.setCoefficient ( globalDofID, FEValues[iterDof] );
828 
829  }
830  }
831  }
832 
833 } // interpolate
834 
835 template <typename MeshType, typename MapType>
836 template<typename vector_type>
837 void
838 FESpace<MeshType, MapType>::interpolateBC ( BCHandler& BCh,
839  vector_type& vect,
840  const Real time)
841 {
842  //
843  // ID nbComp = M_fieldDim; // Number of components of the mesh velocity
844  UInt totalDof = dof().numTotalDof();
845 
846  //
847  ID idDof;
848 
849  if ( !BCh.bcUpdateDone() )
850  {
851  BCh.bcUpdate ( *mesh(), feBd(), dof() );
852  }
853 
854 
855  for ( UInt ibc = 0; ibc < BCh.size(); ++ibc )
856  {
857  if (BCh[ ibc ].type() == Essential)
858  {
859  // Number of components involved in this boundary condition
860  UInt nComp = BCh[ibc].numberOfComponents();
861 
862  for ( ID i = 0; i < BCh[ibc].list_size(); ++i )
863  {
864  // Coordinates of the node where we impose the value
865  Real x = static_cast< const BCIdentifierEssential* > ( BCh[ibc][ i ] ) ->x();
866  Real y = static_cast< const BCIdentifierEssential* > ( BCh[ibc][ i ] ) ->y();
867  Real z = static_cast< const BCIdentifierEssential* > ( BCh[ibc][ i ] ) ->z();
868 
869  for ( ID j = 0; j < nComp; ++j )
870  {
871  // Global Dof
872  idDof = BCh[ibc][ i ] ->id() + BCh[ibc].component ( j ) * totalDof;
874 
875  vect.setCoefficient (idDof, val);
876  }
877  }
878  }
879  }
880 
881 
882 
883 }
884 
885 
886 
887 // this computes vec = \int fct phi_i
888 template <typename MeshType, typename MapType>
889 template<typename vector_type>
890 void
891 FESpace<MeshType, MapType>::l2ScalarProduct ( const function_Type& fct, vector_type& vec, const Real t)
892 {
893 
894  for ( UInt iVol = 0; iVol < this->mesh()->numElements(); iVol++ )
895  {
896  this->fe().update ( this->mesh()->element ( iVol ), UPDATE_QUAD_NODES | UPDATE_WDET );
897 
898  Real f, x, y, z;
899 
900  UInt i, inod, iQuadPt, ic;
901  UInt eleID = this->fe().currentLocalId();
902  Real u_ig;
903 
904  for ( iQuadPt = 0; iQuadPt < this->fe().nbQuadPt(); iQuadPt++ )
905  {
906  x = this->fe().quadNode (iQuadPt, 0);
907  y = this->fe().quadNode (iQuadPt, 1);
908  z = this->fe().quadNode (iQuadPt, 2);
909  for ( ic = 0; ic < M_fieldDim; ic++ )
910  {
911  f = fct ( t, x, y, z, ic );
912  u_ig = 0.;
913  for ( i = 0; i < this->fe().nbFEDof(); i++ )
914  {
915  inod = this->dof().localToGlobalMap ( eleID, i ) + ic * dim();
916  u_ig = f * this->fe().phi ( i, iQuadPt );
917  vec.sumIntoGlobalValues (inod, u_ig * this->fe().weightDet ( iQuadPt ) );
918  }
919 
920  }
921  }
922  }
923 
924  vec.globalAssemble();
925 }
926 
927 
928 
929 template <typename MeshType, typename MapType>
930 template<typename vector_type>
931 Real
932 FESpace<MeshType, MapType>::l20Error ( const function_Type& fexact,
933  const vector_type& vec,
934  const Real time,
935  Real* relError )
936 {
937  Real normU = 0.;
938  Real meanU = 0.;
939  Real mass = 0.;
940  Real sumExact2 = 0.;
941  Real sumExact1 = 0.;
942 
943  for ( UInt iVol = 0; iVol < this->mesh()->numElements(); iVol++ )
944  {
945  this->fe().update ( this->mesh()->element ( iVol ), UPDATE_QUAD_NODES | UPDATE_WDET );
946 
947  normU += elementaryDifferenceL2NormSquare ( vec, fexact, this->fe(), this->dof(), time, M_fieldDim );
948 
949  meanU += elementaryDifferenceIntegral ( vec, fexact, this->fe(), this->dof(), time, M_fieldDim );
950  mass += this->fe().measure();
951  if (relError)
952  {
953  sumExact2 += elementaryFctL2NormSquare ( fexact, this->fe(), time, M_fieldDim );
954  sumExact1 += elementaryFctIntegral ( fexact, this->fe(), time, M_fieldDim );
955  }
956  }
957 
958 
959  Real sendbuff[5] = {mass, meanU, normU, sumExact1, sumExact2};
960  Real recvbuff[5];
961 
962  this->map().comm().SumAll (&sendbuff[0], &recvbuff[0], 5);
963 
964 
965  mass = recvbuff[0];
966  meanU = recvbuff[1];
967  normU = recvbuff[2];
968  sumExact1 = recvbuff[3];
969  sumExact2 = recvbuff[4];
970 
971  Real absError = std::sqrt ( normU - meanU * meanU / mass );
972 
973  if (relError)
974  {
975  Real normExact = std::sqrt ( sumExact2 - sumExact1 * sumExact1 / mass );
976  *relError = absError / normExact;
977  }
978  return absError;
979 }
980 
981 
982 
983 template <typename MeshType, typename MapType>
984 template<typename vector_type>
985 Real
986 FESpace<MeshType, MapType>::l2Error ( const function_Type& fexact,
987  const vector_type& vec,
988  const Real time,
989  Real* relError )
990 {
991  Real normU = 0.;
992  Real sumExact = 0.;
993 
994  for ( UInt iVol = 0; iVol < this->mesh()->numElements(); iVol++ )
995  {
996  if ( this->mesh()->element ( iVol ).isOwned() )
997  {
998  //this->fe().updateFirstDeriv( this->mesh()->element( iVol ) );
999 
1000  // CurrentFE newFE(this->fe().refFE(),this->fe().geoMap(),quadRuleTetra64pt);
1001  this->fe().update (this->mesh()->element ( iVol ), UPDATE_QUAD_NODES | UPDATE_WDET);
1002 
1003  normU += elementaryDifferenceL2NormSquare ( vec, fexact,
1004  this->fe(),
1005  //newFE,
1006  this->dof(),
1007  time,
1008  M_fieldDim );
1009  if (relError)
1010  {
1011  sumExact += elementaryFctL2NormSquare ( fexact,
1012  this->fe(),
1013  time,
1014  M_fieldDim );
1015  }
1016  }
1017  }
1018 
1019 
1020  Real sendbuff[2] = {normU, sumExact};
1021  Real recvbuff[2];
1022 
1023  this->map().comm().SumAll (&sendbuff[0], &recvbuff[0], 2);
1024 
1025  normU = recvbuff[0];
1026  sumExact = recvbuff[1];
1027 
1028  if (relError)
1029  {
1030  *relError = std::sqrt ( normU / sumExact );
1031  }
1032 
1033  return std::sqrt ( normU );
1034 }
1035 
1036 template <typename MeshType, typename MapType>
1037 template<typename function>
1038 Real
1039 FESpace<MeshType, MapType>::l2NormFunction ( const function& f, const Real time)
1040 {
1041  //
1042  //ID nbComp = M_fieldDim; // Number of components of the mesh velocity
1043  //
1044  Real sumExact = 0.;
1045  //
1046  for ( UInt ielem = 0; ielem < this->mesh()->numElements(); ielem++ )
1047  {
1048  this->fe().update ( this->mesh()->element ( ielem ), UPDATE_QUAD_NODES | UPDATE_WDET );
1049 
1050  sumExact += elementaryFctL2NormSquare ( f, this->fe(), time, M_fieldDim );
1051  }
1052 
1053  Real sendbuff[1] = {sumExact};
1054  Real recvbuff[1];
1055 
1056  this->map().comm().SumAll (&sendbuff[0], &recvbuff[0], 1);
1057 
1058  sumExact = recvbuff[0];
1059 
1060  return std::sqrt ( sumExact );
1061 
1062 }
1063 
1064 template<typename MeshType, typename MapType>
1065 template<typename vector_type>
1066 Real
1067 FESpace<MeshType, MapType>:: l2ErrorWeighted (const function_Type& exactSolution,
1068  const vector_type& solution,
1069  const function_Type& weight,
1070  const Real time)
1071 {
1072  // Check that the vector is repeated (needed!)
1073  if (solution.mapType() == Unique)
1074  {
1075  return l2ErrorWeighted (exactSolution, VectorEpetra (solution, Repeated), weight, time);
1076  }
1077 
1078  Real sumOfSquare (0.0);
1079 
1080  // Compute the integral on this processor
1081 
1082  for (UInt iVol (0); iVol < this->mesh()->numElements(); ++iVol)
1083  {
1084  this->fe().update (this->mesh()->element (iVol), UPDATE_QUAD_NODES | UPDATE_WDET);
1085 
1086  for (UInt iQuad (0); iQuad < this->fe().nbQuadPt(); ++iQuad)
1087  {
1088  Real solutionInQuadNode (0.0);
1089 
1090  for (UInt iDim (0); iDim < M_fieldDim; ++iDim)
1091  {
1092  for (UInt iDof (0); iDof < this->fe().nbFEDof(); ++iDof)
1093  {
1094  UInt dofID (this->dof().localToGlobalMap (iVol, iDof) + iDim * this->dof().numTotalDof() );
1095  solutionInQuadNode += this->fe().phi (iDof, iQuad) * solution[dofID];
1096  }
1097 
1098  Real x (this->fe().quadNode (iQuad, 0) );
1099  Real y (this->fe().quadNode (iQuad, 1) );
1100  Real z (this->fe().quadNode (iQuad, 2) );
1101  Real weightInQuadNode (weight (time, x, y, z, iDim) );
1102  Real exactInQuadNode (exactSolution (time, x, y, z, iDim) );
1103 
1104  sumOfSquare += weightInQuadNode
1105  * (exactInQuadNode - solutionInQuadNode)
1106  * (exactInQuadNode - solutionInQuadNode)
1107  * this->fe().wDetJacobian (iQuad);
1108  }
1109  }
1110  }
1111 
1112  // Communicate the results
1113 
1114  Real sendbuff (sumOfSquare);
1115  Real recvbuff;
1116 
1117  this->map().comm().SumAll (&sendbuff, &recvbuff, 1);
1118 
1119  sumOfSquare = recvbuff;
1120 
1121  return std::sqrt (sumOfSquare);
1122 }
1123 
1124 
1125 
1126 
1127 template <typename MeshType, typename MapType>
1128 template<typename function, typename vector_type>
1129 Real
1130 FESpace<MeshType, MapType>::h1Error ( const function& fexact,
1131  const vector_type& vec,
1132  const Real time,
1133  Real* relError )
1134 {
1135  Real normU = 0.;
1136  Real sumExact = 0.;
1137 
1138  for ( UInt iVol = 0; iVol < this->mesh()->numElements(); iVol++ )
1139  {
1140  this->fe().updateFirstDerivQuadPt ( this->mesh()->element ( iVol ) );
1141 
1142  normU += elementaryDifferenceH1NormSquare ( vec, fexact,
1143  this->fe(),
1144  //p1,
1145  this->dof(),
1146  time,
1147  M_fieldDim );
1148  if (relError)
1149  {
1150  sumExact += elementaryFctH1NormSquare ( fexact,
1151  this->fe(),
1152  //p1,
1153  time,
1154  M_fieldDim );
1155  }
1156  }
1157 
1158 
1159  Real sendbuff[2] = {normU, sumExact};
1160  Real recvbuff[2];
1161 
1162  this->map().comm().SumAll (&sendbuff[0], &recvbuff[0], 2);
1163 
1164 
1165  // int me = this->map().Comm().MyPID();
1166 
1167  // if (me == 0)
1168  // {
1169  normU = recvbuff[0];
1170  sumExact = recvbuff[1];
1171 
1172  if (relError)
1173  {
1174  *relError = std::sqrt ( normU / sumExact );
1175  }
1176  // }
1177 
1178  return std::sqrt ( normU );
1179 }
1180 
1181 // Warning! When using this function in parallel, the vector vec HAS TO BE REPEATED!
1182 template <typename MeshType, typename MapType>
1183 template<typename vector_type>
1184 Real
1185 FESpace<MeshType, MapType>::l2Norm ( const vector_type& vec)
1186 {
1187  //
1188  ID nbComp = M_fieldDim; // Number of components of the mesh velocity
1189  //
1190  Real norm = 0.;
1191  //
1192  for ( UInt ielem = 0; ielem < this->mesh()->numElements(); ielem++ )
1193  {
1194  //UInt elem = M_FESpace.mesh()->element( ielem ).id();
1195  this->fe().update ( this->mesh()->element ( ielem ), UPDATE_QUAD_NODES | UPDATE_WDET );
1196  //
1197  norm += elementaryL2NormSquare ( vec, this->fe(), this->dof(), nbComp );
1198  }
1199 
1200  Real sendbuff[1] = {norm};
1201  Real recvbuff[1];
1202 
1203  this->map().comm().SumAll (&sendbuff[0], &recvbuff[0], 1);
1204 
1205  norm = recvbuff[0];
1206 
1207  return std::sqrt ( norm );
1208 
1209 }
1210 
1211 
1212 template <typename MeshType, typename MapType>
1213 template<typename vector_type>
1214 Real
1215 FESpace<MeshType, MapType>::h1Norm (const vector_type& vec)
1216 {
1217  //
1218  ID nbComp = M_fieldDim; // Number of components of the mesh velocity
1219  //
1220  Real norm = 0.;
1221  //
1222  for ( UInt ielem = 0; ielem < this->mesh()->numElements(); ielem++ )
1223  {
1224  //UInt elem = M_FESpace.mesh()->element( ielem ).id();
1225  this->fe().updateFirstDerivQuadPt ( this->mesh()->element ( ielem ) );
1226  //
1227  // for ( UInt j = 0; j < nbComp; ++j)
1228  norm += elementaryH1NormSquare ( vec, this->fe(), this->dof(), nbComp );
1229  }
1230 
1231  Real sendbuff[1] = {norm};
1232  Real recvbuff[1];
1233 
1234  this->map().comm().SumAll (&sendbuff[0], &recvbuff[0], 1);
1235 
1236  norm = recvbuff[0];
1237 
1238  return std::sqrt ( norm );
1239 
1240 }
1241 
1242 
1243 
1244 template<typename MeshType, typename MapType>
1245 template<typename point_type, typename vector_type>
1246 Real
1247 FESpace<MeshType, MapType>::
1248 feInterpolateValue (const ID& elementID, const vector_type& solutionVector, const point_type& pt, const UInt& component ) const
1249 {
1250  // The vector has to be repeated, so if it is not, we make is repeated and call this function again.
1251  if (solutionVector.mapType() != Repeated )
1252  {
1253  vector_type repeatedSolutionVector (solutionVector, Repeated);
1254  return feInterpolateValue (elementID, repeatedSolutionVector, pt, component);
1255  }
1256 
1257  // Make sur everything is up to date
1258  M_fe->update ( M_mesh->element ( elementID ), UPDATE_ONLY_CELL_NODES);
1259 
1260  // Map the point back to the ref FE
1261  Real hat_x (0);
1262  Real hat_y (0);
1263  Real hat_z (0);
1264  Real x (0);
1265  Real y (0);
1266  Real z (0);
1267 
1268  if (pt.size() >= 1)
1269  {
1270  x = pt[0];
1271  }
1272  if (pt.size() >= 2)
1273  {
1274  y = pt[1];
1275  }
1276  if (pt.size() >= 3)
1277  {
1278  z = pt[2];
1279  }
1280 
1281  M_fe->coorBackMap (x, y, z, hat_x, hat_y, hat_z);
1282 
1283  // Store the number of local DoF
1284  UInt nDof (dof().numLocalDof() );
1285  UInt totalDof (dof().numTotalDof() );
1286 
1287  // Initialization
1288  Real value (0);
1289 
1290  // Loop over the DoFs
1291  for (UInt iter_dof (0); iter_dof < nDof ; ++iter_dof)
1292  {
1293  // The global ID of the selected dof
1294  // This should be changed in case of a VECTORIAL FE
1295 
1296  ID globalDofID (component * totalDof + dof().localToGlobalMap (elementID, iter_dof) ); // iter_dof -> dofID
1297 
1298  // Make the accumulation
1299  // std::cout << M_refFE->phi(iter_dof, hat_x, hat_y, hat_z) << " " << iter_dof << " " << hat_x << " " << hat_y << " " << hat_z << std::endl;
1300  value += solutionVector[globalDofID] * M_refFE->phi (iter_dof, hat_x, hat_y, hat_z);
1301  }
1302 
1303  return value;
1304 }
1305 
1306 
1307 template<typename MeshType, typename MapType>
1308 template<typename point_type, typename vector_type>
1309 Real
1310 FESpace<MeshType, MapType>::
1311 feInterpolateValueLocal (const ID& elementID, const vector_type& solutionVector, const point_type& pt ) const
1312 {
1313  // Make sur everything is up to date
1314  M_fe->update ( M_mesh->element ( elementID ), UPDATE_ONLY_CELL_NODES);
1315 
1316  // Map the point back to the ref FE
1317  Real hat_x (0);
1318  Real hat_y (0);
1319  Real hat_z (0);
1320 
1321  Real x (0);
1322  Real y (0);
1323  Real z (0);
1324 
1325  if (pt.size() >= 1)
1326  {
1327  x = pt[0];
1328  }
1329  if (pt.size() >= 2)
1330  {
1331  y = pt[1];
1332  }
1333  if (pt.size() >= 3)
1334  {
1335  z = pt[2];
1336  }
1337 
1338  M_fe->coorBackMap (x, y, z, hat_x, hat_y, hat_z);
1339 
1340  // Store the number of local DoF
1341  UInt nDof (dof().numLocalDof() );
1342 
1343  // Initialization
1344  Real value (0);
1345 
1346  // Loop over the DoFs
1347  for (UInt iter_dof (0); iter_dof < nDof ; ++iter_dof)
1348  {
1349  // Make the accumulation
1350  value += solutionVector[iter_dof] * M_refFE->phi (iter_dof, hat_x, hat_y, hat_z);
1351  }
1352 
1353  return value;
1354 }
1355 
1356 
1357 template<typename MeshType, typename MapType>
1358 template<typename point_type, typename vector_type>
1359 Real
1360 FESpace<MeshType, MapType>::
1361 feInterpolateGradient (const ID& elementID, const vector_type& solutionVector, const point_type& pt,
1362  const UInt& gradientElement, const UInt& component ) const
1363 {
1364  // The vector has to be repeated, so if it is not, we make is repeated and call this function again.
1365  if (solutionVector.getMaptype() != Repeated )
1366  {
1367  vector_type repeatedSolutionVector (solutionVector, Repeated);
1368  return feInterpolateGradient (elementID, repeatedSolutionVector, pt, gradientElement, component);
1369  }
1370 
1371 
1372  // Make sur everything is up to date
1373  M_fe->updateFirstDeriv ( M_mesh->element ( elementID ) );
1374 
1375  // Map the point back to the ref FE
1376  Real hat_x (0);
1377  Real hat_y (0);
1378  Real hat_z (0);
1379  Real x (0);
1380  Real y (0);
1381  Real z (0);
1382 
1383  if (pt.size() >= 1)
1384  {
1385  x = pt[0];
1386  }
1387  if (pt.size() >= 2)
1388  {
1389  y = pt[1];
1390  }
1391  if (pt.size() >= 3)
1392  {
1393  z = pt[2];
1394  }
1395 
1396  M_fe->coorBackMap (x, y, z, hat_x, hat_y, hat_z);
1397 
1398  // Store the number of local DoF
1399  UInt nDof (dof().numLocalDof() );
1400  UInt totalDof (dof().numTotalDof() );
1401 
1402  // Initialization
1403  Real grad (0);
1404 
1405  // Loop over the DoFs
1406  std::vector<Real> invJac (3, 0);
1407  invJac[0] = M_fe->pointInverseJacobian (hat_x, hat_y, hat_z, gradientElement, 0);
1408  invJac[1] = M_fe->pointInverseJacobian (hat_x, hat_y, hat_z, gradientElement, 1);
1409  invJac[2] = M_fe->pointInverseJacobian (hat_x, hat_y, hat_z, gradientElement, 2);
1410 
1411  for (UInt iter_dof (0); iter_dof < nDof ; ++iter_dof)
1412  {
1413  // The global ID of the selected dof
1414  ID globalDofID (totalDof * component + dof().localToGlobalMap (elementID, iter_dof) );
1415 
1416  for (UInt iter_dim (0); iter_dim < 3; ++iter_dim)
1417  {
1418  grad += solutionVector (globalDofID) * M_refFE->dPhi (iter_dof, iter_dim, hat_x, hat_y, hat_z)
1419  * invJac[iter_dim];
1420  }
1421  }
1422 
1423  return grad;
1424 }
1425 
1426 
1427 template<typename MeshType, typename MapType>
1428 template<typename point_type, typename vector_type>
1429 Real
1430 FESpace<MeshType, MapType>::
1431 feInterpolateGradientLocal (const ID& elementID, const vector_type& solutionVector, const point_type& pt,
1432  const UInt& gradientElement ) const
1433 {
1434  // Make sur everything is up to date
1435  M_fe->updateFirstDeriv ( M_mesh->element ( elementID ) );
1436 
1437  // Map the point back to the ref FE
1438  Real hat_x (0);
1439  Real hat_y (0);
1440  Real hat_z (0);
1441  Real x (0);
1442  Real y (0);
1443  Real z (0);
1444 
1445  if (pt.size() >= 1)
1446  {
1447  x = pt[0];
1448  }
1449  if (pt.size() >= 2)
1450  {
1451  y = pt[1];
1452  }
1453  if (pt.size() >= 3)
1454  {
1455  z = pt[2];
1456  }
1457 
1458  M_fe->coorBackMap (x, y, z, hat_x, hat_y, hat_z);
1459 
1460  // Store the number of local DoF
1461  UInt nDof (dof().numLocalDof() );
1462 
1463  // Initialization
1464  Real grad (0);
1465 
1466  // Loop over the DoFs
1467  for (UInt iter_dof (0); iter_dof < nDof ; ++iter_dof)
1468  {
1469 
1470  for (UInt iter_dim (0); iter_dim < 3; ++iter_dim)
1471  {
1472  grad += solutionVector[iter_dof] * M_refFE->dPhi (iter_dof, iter_dim, hat_x, hat_y, hat_z)
1473  * M_fe->pointInverseJacobian (hat_x, hat_y, hat_z, gradientElement, iter_dim);
1474  }
1475  }
1476 
1477  return grad;
1478 }
1479 
1480 
1481 template<typename MeshType, typename MapType>
1482 template<typename vector_type>
1483 vector_type
1484 FESpace<MeshType, MapType>::
1485 feToFEInterpolate (const FESpace<mesh_Type, map_Type>& OriginalSpace,
1486  const vector_type& OriginalVector, const MapEpetraType& outputMapType) const
1487 {
1488  // This method just check that everything is all right and then call the
1489  // appropriate method __To__Interpolate if needed.
1490 
1491  // First, check that the interpolation is possible
1492  ASSERT (fieldDim() == OriginalSpace.fieldDim() ||
1493  OriginalSpace.refFE().type() == FE_RT0_TETRA_3D ||
1494  OriginalSpace.refFE().type() == FE_RT0_TRIA_2D, "Incompatible field dimension for interpolation");
1495  ASSERT (refFE().shape() == OriginalSpace.refFE().shape() , "Incompatible element shape for interpolation");
1496 
1497 
1498  std::shared_ptr<vector_type> InterpolatedVectorPtr;
1499 
1500  // If the spaces are the same, just return the original vector
1501  if (refFE().type() == OriginalSpace.refFE().type() )
1502  {
1503  //return OriginalVector;
1504  InterpolatedVectorPtr.reset ( new vector_type (OriginalVector) );
1505  }
1506 
1507  // Distinguish the other cases
1508  else if ( ( (refFE().type() == FE_P1_3D) && ( (OriginalSpace.refFE().type() == FE_P1bubble_3D) || (OriginalSpace.refFE().type() == FE_P2_3D) ) ) ||
1509  ( (refFE().type() == FE_P1_2D) && ( (OriginalSpace.refFE().type() == FE_P1bubble_2D) || (OriginalSpace.refFE().type() == FE_P2_3D) ) ) ||
1510  ( (refFE().type() == FE_P1_2D) && ( OriginalSpace.refFE().type() == FE_P2_2D ) ) ||
1511  ( (refFE().type() == FE_Q1_3D) && ( OriginalSpace.refFE().type() == FE_Q2_3D ) ) ||
1512  ( (refFE().type() == FE_Q1_2D) && ( OriginalSpace.refFE().type() == FE_Q2_2D ) ) ||
1513  ( (refFE().type() == FE_P1bubble_3D) && (OriginalSpace.refFE().type() == FE_P1_3D) ) ||
1514  ( (refFE().type() == FE_P1bubble_2D) && (OriginalSpace.refFE().type() == FE_P1_2D) ) )
1515  {
1516  InterpolatedVectorPtr.reset (new vector_type ( linearInterpolate (OriginalSpace, OriginalVector) ) );
1517  }
1518  else
1519  {
1520  // The following methods work only if the map is repeated.
1521  // if the original vector is repeated, make it repeated and recall this method.
1522  if ( OriginalVector.mapType() == Unique )
1523  {
1524  const vector_type OriginalRepeated (OriginalVector, Repeated);
1525  return feToFEInterpolate (OriginalSpace, OriginalRepeated);
1526  }
1527 
1528  if ( ( (refFE().type() == FE_P2_3D) && ( (OriginalSpace.refFE().type() == FE_P1bubble_3D) || (OriginalSpace.refFE().type() == FE_P1_3D) ) ) ||
1529  ( (refFE().type() == FE_P2_2D) && ( (OriginalSpace.refFE().type() == FE_P1bubble_2D) || (OriginalSpace.refFE().type() == FE_P1_2D) ) ) ||
1530  ( (refFE().type() == FE_P2_2D) && ( OriginalSpace.refFE().type() == FE_P1_2D ) ) )
1531  {
1532  InterpolatedVectorPtr.reset (new vector_type ( P2Interpolate (OriginalSpace, OriginalVector) ) );
1533  }
1534 
1535  else if ( ( OriginalSpace.refFE().type() == FE_RT0_TETRA_3D) || (refFE().type() == FE_RT0_TETRA_3D) ||
1536  ( OriginalSpace.refFE().type() == FE_RT0_TRIA_2D) || (refFE().type() == FE_RT0_TRIA_2D) )
1537  {
1538  if (refFE().type() == FE_P0_3D || refFE().type() == FE_P0_2D)
1539  {
1540  InterpolatedVectorPtr.reset (new vector_type ( RT0ToP0Interpolate (OriginalSpace, OriginalVector) ) );
1541  }
1542  else
1543  {
1544  ERROR_MSG (" The interpolation with this host space has not been yet implemented. Please, add it!");
1545  }
1546  }
1547  else
1548  {
1549  InterpolatedVectorPtr.reset (new vector_type ( interpolateGeneric ( OriginalSpace, OriginalVector) ) );
1550  }
1551  }
1552 
1553  if (InterpolatedVectorPtr->mapType() == outputMapType)
1554  {
1555  return *InterpolatedVectorPtr;
1556  }
1557  else
1558  {
1559  // Here we do need to use the combine mode "Insert": the default combine mode
1560  // is "Add". In fact, when we convert from a Repeated to a unique Map, as we pass several times on the same DoF, the values would be added, what would
1561  // be wrong. Instead, we keep only one value (which anyway should be always the same for continuous
1562  // finite element).
1563  return vector_type (*InterpolatedVectorPtr, outputMapType, Insert);
1564  }
1565 }
1566 
1567 
1568 template<typename MeshType, typename MapType>
1569 template<typename vector_type>
1570 vector_type
1571 FESpace<MeshType, MapType>::
1572 gradientRecovery (const vector_type& solution, const UInt& dxi) const
1573 {
1574  if (solution.mapType() != Repeated)
1575  {
1576  return gradientRecovery (vector_type (solution, Repeated), dxi);
1577  }
1578 
1579  Real refElemArea (0); //area of reference element
1580 
1581  //compute the area of reference element
1582  for (UInt iq = 0; iq < M_Qr->nbQuadPt(); iq++)
1583  {
1584  refElemArea += M_Qr->weight (iq);
1585  }
1586 
1587  // Define a special quadrature rule for the interpolation
1588  QuadratureRule interpQuad;
1589  interpQuad.setDimensionShape (shapeDimension (M_refFE->shape() ), M_refFE->shape() );
1590  Real wQuad (refElemArea / M_refFE->nbDof() );
1591 
1592  for (UInt i (0); i < M_refFE->nbDof(); ++i) //nbRefCoor
1593  {
1594  interpQuad.addPoint (QuadraturePoint (M_refFE->xi (i), M_refFE->eta (i), M_refFE->zeta (i), wQuad) );
1595  }
1596 
1597  // Initialization of the vectors
1598  vector_type patchArea (solution, Repeated);
1599  patchArea *= 0.0;
1600 
1601  vector_type gradientSum (solution, Repeated);
1602  gradientSum *= 0.0;
1603 
1604 
1605  UInt totalNumberElements (M_mesh->numElements() );
1606  UInt numberLocalDof (M_dof->numLocalDof() );
1607 
1608  CurrentFE interpCFE (*M_refFE, getGeometricMap (*M_mesh ), interpQuad);
1609 
1610  // Loop over the cells
1611  for (UInt iterElement (0); iterElement < totalNumberElements; ++iterElement)
1612  {
1613  interpCFE.update (mesh()->element (iterElement), UPDATE_DPHI | UPDATE_WDET );
1614 
1615  for (UInt iterDof (0); iterDof < numberLocalDof; ++iterDof)
1616  {
1617  for (UInt iDim (0); iDim < M_fieldDim; ++iDim)
1618  {
1619  ID globalDofID (dof().localToGlobalMap (iterElement, iterDof) + iDim * dof().numTotalDof() );
1620 
1621  patchArea[globalDofID] += interpCFE.measure();
1622  for (UInt iterDofGrad (0); iterDofGrad < numberLocalDof; ++iterDofGrad)
1623  {
1624  ID globalDofIDGrad (dof().localToGlobalMap (iterElement, iterDofGrad) + iDim * dof().numTotalDof() );
1625  gradientSum[globalDofID] += interpCFE.measure() * solution[globalDofIDGrad] * interpCFE.dphi (iterDofGrad, dxi, iterDof);
1626  }
1627  }
1628  }
1629  }
1630 
1631  // Assembly
1632  return vector_type (gradientSum, Unique, Add) / vector_type (patchArea, Unique, Add);
1633 }
1634 
1635 template<typename MeshType, typename MapType>
1636 template<typename vector_type>
1637 vector_type
1638 FESpace<MeshType, MapType>::
1639 laplacianRecovery (const vector_type& solution) const
1640 {
1641  if (solution.getMaptype() != Repeated)
1642  {
1643  return laplacianRecovery (vector_type (solution, Repeated) );
1644  }
1645 
1646  vector_type laplacian (solution);
1647  laplacian *= 0.0;
1648 
1649  for (UInt iterDim (0); iterDim < 3; ++iterDim)
1650  {
1651  laplacian += gradientRecovery (gradientRecovery (solution, iterDim), iterDim);
1652  }
1653  return laplacian;
1654 }
1655 
1656 
1657 
1658 // ===================================================
1659 // Set Methods
1660 // ===================================================
1661 
1662 // Set FE space (default standard parameters)
1663 template <typename MeshType, typename MapType>
1664 inline void
1665 FESpace<MeshType, MapType>::setSpace ( const std::string& space, UInt dimension )
1666 {
1667  switch (dimension)
1668  {
1669  // 1D case
1670  case 1:
1671  switch ( M_spaceMap[space] )
1672  {
1673  case P0 :
1674  M_refFE = &feSegP0;
1675  M_Qr = &quadRuleSeg1pt;
1676  M_bdQr = &quadRuleNode1pt;
1677  case P1 :
1678  M_refFE = &feSegP1;
1679  M_Qr = &quadRuleSeg2pt;
1680  M_bdQr = &quadRuleNode1pt;
1681  break;
1682 
1683  case P1_HIGH :
1684  M_refFE = &feSegP1;
1685  M_Qr = &quadRuleSeg3pt;
1686  M_bdQr = &quadRuleNode1pt;
1687  break;
1688 
1689  // In 1D, P1Bubble are "somehow" equivalent to P2, so just use those (same pattern, same dimension of the system).
1690  case P1Bubble :
1691  case P2 :
1692  M_refFE = &feSegP2;
1693  M_Qr = &quadRuleSeg3pt;
1694  M_bdQr = &quadRuleNode1pt;
1695  break;
1696 
1697  case P2_HIGH :
1698  M_refFE = &feSegP2;
1699  M_Qr = &quadRuleSeg4pt;
1700  M_bdQr = &quadRuleNode1pt;
1701  break;
1702 
1703  default :
1704  std::cout << "!!! WARNING: Space " << space << "not implemented for " << dimension << "D FESpaces!" << std::endl;
1705  break;
1706  }
1707  break;
1708 
1709  // 2D case
1710  case 2:
1711  switch ( M_spaceMap[space] )
1712  {
1713  case P0 :
1714  M_refFE = &feTriaP0;
1715  M_Qr = &quadRuleTria3pt;
1716  M_bdQr = &quadRuleSeg2pt;
1717  case P1 :
1718  M_refFE = &feTriaP1;
1719  M_Qr = &quadRuleTria3pt;
1720  M_bdQr = &quadRuleSeg2pt;
1721  break;
1722 
1723  case P1_HIGH :
1724  M_refFE = &feTriaP1;
1725  M_Qr = &quadRuleTria6pt;
1726  M_bdQr = &quadRuleSeg3pt;
1727  break;
1728 
1729  case P1Bubble :
1730  M_refFE = &feTriaP1bubble;
1731  M_Qr = &quadRuleTria6pt;
1732  M_bdQr = &quadRuleSeg2pt;
1733  break;
1734 
1735  case P2 :
1736  M_refFE = &feTriaP2;
1737  M_Qr = &quadRuleTria6pt;
1738  M_bdQr = &quadRuleSeg3pt;
1739  break;
1740 
1741  case P2_HIGH :
1742  M_refFE = &feTriaP2;
1743  M_Qr = &quadRuleTria7pt;
1744  M_bdQr = &quadRuleSeg3pt;
1745  break;
1746 
1747  default :
1748  std::cout << "!!! WARNING: Space " << space << "not implemented for " << dimension << "D FESpaces!" << std::endl;
1749  break;
1750  }
1751  break;
1752 
1753  // 3D case
1754  case 3:
1755  switch ( M_spaceMap[space] )
1756  {
1757  case P0 :
1758  M_refFE = &feTetraP0;
1759  M_Qr = &quadRuleTetra4pt;
1760  M_bdQr = &quadRuleTria3pt;
1761  break;
1762 
1763  case P1 :
1764  M_refFE = &feTetraP1;
1765  M_Qr = &quadRuleTetra4pt;
1766  M_bdQr = &quadRuleTria3pt;
1767  break;
1768 
1769  case P1_HIGH :
1770  M_refFE = &feTetraP1;
1771  M_Qr = &quadRuleTetra15pt;
1772  M_bdQr = &quadRuleTria4pt;
1773  break;
1774 
1775  case P1Bubble :
1776  M_refFE = &feTetraP1bubble;
1777  M_Qr = &quadRuleTetra64pt;
1778  M_bdQr = &quadRuleTria3pt;
1779  break;
1780 
1781  case P2 :
1782  M_refFE = &feTetraP2;
1783  M_Qr = &quadRuleTetra15pt;
1784  M_bdQr = &quadRuleTria4pt;
1785  break;
1786 
1787  case P2_HIGH :
1788  M_refFE = &feTetraP2;
1789  M_Qr = &quadRuleTetra64pt;
1790  M_bdQr = &quadRuleTria4pt;
1791  break;
1792 
1793  case P2Bubble :
1794  M_refFE = &feTetraP2tilde;
1795  M_Qr = &quadRuleTetra64pt;
1796  M_bdQr = &quadRuleTria4pt;
1797  break;
1798 
1799  default :
1800  std::cout << "!!! WARNING: Space " << space << "not implemented for " << dimension << "D FESpaces!" << std::endl;
1801  break;
1802  }
1803  break;
1804 
1805  // Other dimensions not supported
1806  default:
1807  ERROR_MSG ("Error! This dimension is not supported by LifeV.\n");
1808  }
1809 }
1810 
1811 template<typename MeshType, typename MapType>
1812 void
1813 FESpace<MeshType, MapType>::
1814 setQuadRule (const QuadratureRule& Qr)
1815 {
1816  M_Qr = &Qr;
1817  M_fe.reset ( new CurrentFE ( *M_refFE, getGeometricMap ( *M_mesh ), *M_Qr ) );
1818 }
1819 
1820 
1821 template<typename MeshType, typename MapType>
1822 void
1823 FESpace<MeshType, MapType>::
1824 setBdQuadRule (const QuadratureRule& Qr)
1825 {
1826  M_bdQr = &Qr;
1827  resetBoundaryFE();
1828 }
1829 
1830 
1831 // ===================================================
1832 // Private Methods
1833 // ===================================================
1834 /*
1835 template<typename MeshType, typename MapType>
1836 void
1837 FESpace<MeshType,MapType>::
1838 createMap(const commPtr_Type& commptr)
1839 {
1840 // Build Map
1841 MapType map( *M_refFE, *M_mesh, commptr );
1842 // If more than one field is present the map is
1843 // duplicated by offsetting the DOFs
1844 for ( UInt ii = 0; ii < M_fieldDim; ++ii )
1845  *M_map += map;
1846 }
1847 */
1848 template<typename MeshType, typename MapType>
1849 void
1850 FESpace<MeshType, MapType>::
1851 createMap (const commPtr_Type& commptr)
1852 {
1853  // Against dummies
1854  ASSERT_PRE (this->M_dof->numTotalDof() > 0, " Cannot create FeSpace with no degrees of freedom");
1855 
1856  // get globalElements list from DOF
1857  typename MapType::mapData_Type mapData = this->M_dof->createMapData ( *this->M_mesh );
1858  // Create the map
1859  MapType map ( mapData, commptr );
1860 
1861  // Store the map. If more than one field is present the map is
1862  // duplicated by offsetting the DOFs
1863  for ( UInt ii = 0; ii < M_fieldDim; ++ii )
1864  {
1865  *M_map += map;
1866  }
1867 }
1868 
1869 
1870 template<typename MeshType, typename MapType>
1871 void
1872 FESpace<MeshType, MapType>::
1873 resetBoundaryFE()
1874 {
1875  if (M_refFE->hasBoundaryFE() )
1876  {
1877  M_feBd.reset (new CurrentFEManifold ( M_refFE->boundaryFE(), getGeometricMap ( *M_mesh ).boundaryMap(), *M_bdQr ) );
1878  }
1879 }
1880 
1881 
1882 template<typename MeshType, typename MapType>
1883 template<typename vector_type>
1884 vector_type
1885 FESpace<MeshType, MapType>::
1886 interpolateGeneric ( const FESpace<mesh_Type, map_Type>& OriginalSpace,
1887  const vector_type& OriginalVector) const
1888 {
1889 
1890  vector_type Interpolated (map(), Repeated);
1891 
1892  // Initialization of the dimensions of the vectors
1893  UInt size_comp_in = OriginalSpace.dim();
1894 
1895  // number of local DOF
1896  UInt numberLocalDof (M_dof->numLocalDof() );
1897 
1898  Real xi, yi, zi;
1899 
1900  //vector containing basis function evaluated in the nodes of the current FE element
1901  std::vector<Real> phi (OriginalSpace.dof().numLocalDof() *numberLocalDof, 0.);
1902 
1903  //vector containing the nodal values of the current FE element
1904  std::vector<std::vector<Real> > nodalValues (M_fieldDim, std::vector<Real> (numberLocalDof, 0.) );
1905 
1906  //vector containing basis function weights on the current FE element
1907  std::vector<Real> FEValues (numberLocalDof, 0.);
1908 
1909  //Computing basis function values in the nodes of the current FE element (same values for every element)
1910  for ( UInt iterDof = 0 ; iterDof < numberLocalDof ; ++iterDof )
1911  {
1912  xi = M_refFE->xi (iterDof);
1913  yi = M_refFE->eta (iterDof);
1914  zi = M_refFE->zeta (iterDof);
1915  for (UInt iterDofOrig (0) ; iterDofOrig < OriginalSpace.dof().numLocalDof(); ++iterDofOrig)
1916  {
1917  phi[iterDofOrig * numberLocalDof + iterDof] += OriginalSpace.refFE().phi (iterDofOrig, xi, yi, zi);
1918  }
1919  }
1920 
1921  //Loop over the mesh elements
1922  for ( UInt iElem (0); iElem < M_mesh->numElements(); ++iElem )
1923  {
1924  //computation the nodal values on each element
1925  for ( UInt iterDof = 0 ; iterDof < numberLocalDof ; ++iterDof )
1926  for (UInt iterDofOrig (0) ; iterDofOrig < OriginalSpace.dof().numLocalDof(); ++iterDofOrig)
1927  {
1928  size_t index = OriginalSpace.dof().localToGlobalMap ( iElem, iterDofOrig );
1929  for ( UInt iDim = 0; iDim < M_fieldDim; ++iDim )
1930  {
1931  nodalValues[iDim][iterDof] += OriginalVector[iDim * size_comp_in + index] * phi[iterDofOrig * numberLocalDof + iterDof];
1932  }
1933  }
1934 
1935  //loop over field dimension
1936  for ( UInt iDim = 0; iDim < M_fieldDim; ++iDim )
1937  {
1938  FEValues = M_refFE->nodalToFEValues (nodalValues[iDim]); //needed for non-Lagrangian elements
1939  for ( UInt iterDof (0) ; iterDof < numberLocalDof; ++iterDof )
1940  {
1941  ID globalDofId (M_dof->localToGlobalMap ( iElem, iterDof ) + iDim * M_dim);
1942 
1943  // compute the value of the function and set it
1944  Interpolated.setCoefficient (globalDofId, FEValues[iterDof]);
1945  nodalValues[iDim][iterDof] = 0;
1946  }
1947  }
1948  }
1949 
1950  return Interpolated;
1951 }
1952 
1953 // This method returns a vector with Unique map.
1954 //P2, P1bubble -> P1
1955 //P1 -> P1bubble
1956 //Q2 -> Q1
1957 template<typename MeshType, typename MapType>
1958 template<typename vector_type>
1959 vector_type
1960 FESpace<MeshType, MapType>::
1961 linearInterpolate (const FESpace<mesh_Type, map_Type>& OriginalSpace,
1962  const vector_type& OriginalVector) const
1963 {
1964  // Create a zero vector.
1965  vector_type Interpolated (map(), Unique);
1966  UInt totalDofsOriginal (OriginalSpace.dof().numTotalDof() );
1967  UInt totalDofsPresent (dof().numTotalDof() );
1968  UInt myLinearDofs;
1969 
1970  if (totalDofsPresent > totalDofsOriginal) //P1 -> P1bubble case
1971  {
1972  myLinearDofs = OriginalSpace.map().map (Unique)->NumMyElements() / fieldDim();
1973  }
1974  else //other cases
1975  {
1976  myLinearDofs = map().map (Unique)->NumMyElements() / fieldDim();
1977  }
1978 
1979  //we exploit the fact that the first DOFs of P1b, P2 vectors are the same of P1 ones.
1980  for (UInt j = 0; j < myLinearDofs; j++)
1981  {
1982  UInt ig1 = map().map (Unique)->MyGlobalElements() [j];
1983  UInt ig2 = OriginalSpace.map().map (Unique)->MyGlobalElements() [j];
1984  for (UInt iComponent (0); iComponent < fieldDim(); ++iComponent)
1985  {
1986  Interpolated[ig1 + iComponent * totalDofsPresent] = OriginalVector[ig2 + iComponent * totalDofsOriginal];
1987  }
1988  }
1989 
1990  return Interpolated;
1991 }
1992 
1993 
1994 //P1 -> P2
1995 //P1bubble -> P2
1996 template<typename MeshType, typename MapType>
1997 template<typename vector_type>
1998 vector_type
1999 FESpace<MeshType, MapType>::
2000 P2Interpolate (const FESpace<mesh_Type, map_Type>& OriginalSpace,
2001  const vector_type& OriginalVector) const
2002 {
2003  // Create a zero vector.
2004  vector_type Interpolated (map(), Repeated);
2005  Interpolated *= 0.0;
2006 
2007  // Some constants (avoid recomputing them each time used)
2008  UInt FieldDim (fieldDim() );
2009 
2010  UInt numElements (mesh()->numElements() );
2011 
2012  UInt totalDofsOriginal (OriginalSpace.dof().numTotalDof() );
2013  UInt totalDofsPresent (dof().numTotalDof() );
2014  UInt localDofsPresent (dof().numLocalDof() );
2015 
2016  // A vector to store the values to set in the dofs
2017  std::vector<Real> DofValues (localDofsPresent, 0.0);
2018 
2019  // Loop over the elements to get the values
2020  for ( ID iElem = 0; iElem < numElements ; ++iElem )
2021  {
2022  UInt elemId (mesh()->element (iElem).localId() );
2023 
2024  // In the file /lifefem/ReferenceElement.hpp, we can see that the dofs for P1
2025  // are the first ones of the P2 dofs. We have then to recompute the values
2026  // in the "face" dofs of the P2 element. Moreover, the bubble is zero on the
2027  // faces of the element. It gives then no contribution.
2028 
2029  for (UInt iComponent (0); iComponent < FieldDim; ++iComponent)
2030  {
2031  // Get the values in the vertices
2032  for (UInt iP1dof (0); iP1dof < 4; ++iP1dof)
2033  {
2034  ID globalDofID_original (iComponent * totalDofsOriginal + OriginalSpace.dof().localToGlobalMap (elemId, iP1dof) );
2035 
2036  DofValues[iP1dof] = OriginalVector[globalDofID_original];
2037  }
2038 
2039  // Compute the values in the faces
2040  DofValues[4] = 0.5 * (DofValues[0] + DofValues[1]);
2041  DofValues[5] = 0.5 * (DofValues[1] + DofValues[2]);
2042  DofValues[6] = 0.5 * (DofValues[0] + DofValues[2]);
2043  DofValues[7] = 0.5 * (DofValues[0] + DofValues[3]);
2044  DofValues[8] = 0.5 * (DofValues[1] + DofValues[3]);
2045  DofValues[9] = 0.5 * (DofValues[2] + DofValues[3]);
2046 
2047  // Now set them
2048  for (UInt iP2dof (0); iP2dof < localDofsPresent; ++iP2dof)
2049  {
2050  ID globalDofID_present (iComponent * totalDofsPresent + dof().localToGlobalMap (elemId, iP2dof) );
2051 
2052  Interpolated[globalDofID_present] = DofValues[iP2dof];
2053  }
2054 
2055  }
2056  }
2057 
2058  return Interpolated;
2059 }
2060 
2061 
2062 
2063 
2064 template<typename MeshType, typename MapType>
2065 template<typename vector_type>
2066 vector_type
2067 FESpace<MeshType, MapType>::
2068 RT0ToP0Interpolate (const FESpace<mesh_Type, map_Type>& OriginalSpace,
2069  const vector_type& OriginalVector) const
2070 {
2071  // Create a zero vector.
2072  vector_type Interpolated (map(), Repeated);
2073  Interpolated *= 0.0;
2074 
2075  // Field dimension of the problem.
2076  const UInt FieldDim (fieldDim() );
2077 
2078  // Total number of mesh elements.
2079  const UInt numElements (mesh()->numElements() );
2080 
2081  // Total d.o.f. in the present FESpace.
2082  const UInt totalDofsPresent (dof().numTotalDof() );
2083 
2084  // Loop over the elements to get the values. To compute the value we use the Piola transformation.
2085  for ( ID iElem (0); iElem < numElements ; ++iElem )
2086  {
2087 
2088  // Map between local and global mesh.
2089  const UInt elemId (mesh()->element (iElem).localId() );
2090 
2091  // Current and reference barycenter, Jacobian of the map.
2092  Vector3D barCurrentFE, barRefFE, Jac;
2093 
2094  // Update the current element of the P0 vector space.
2095  M_fe->update (this->mesh()->element (elemId), UPDATE_QUAD_NODES | UPDATE_WDET);
2096 
2097  // Store the number of local DoF
2098  const UInt nDof (OriginalSpace.dof().numLocalDof() );
2099 
2100  // Get the coordinate of the barycenter of the current element of ID iElem.
2101  M_fe->barycenter ( barCurrentFE[0], barCurrentFE[1], barCurrentFE[2] );
2102 
2103  // Update the barycenter to the reference finite element.
2104  M_fe->coorBackMap ( barCurrentFE[0], barCurrentFE[1], barCurrentFE[2],
2105  barRefFE[0], barRefFE[1], barRefFE[2] );
2106 
2107  // Compute the determinant of the Jacobian in the barycenter of the reference finite element.
2108  const Real det = M_fe->pointDetJacobian (barRefFE[0], barRefFE[1], barRefFE[2]);
2109 
2110  // Loop on the vector component of P0 element.
2111  for (UInt iComponent (0); iComponent < FieldDim; ++iComponent)
2112  {
2113  Real value (0);
2114 
2115  // The Jacobian evaluated in the three points of the barycenter of each component.
2116  for ( UInt localComponent (0); localComponent < FieldDim; ++localComponent )
2117  {
2118  Jac[localComponent] = M_fe->pointJacobian ( barRefFE[0], barRefFE[1], barRefFE[2],
2119  iComponent, localComponent);
2120  }
2121 
2122  const UInt iGlobalFacePresent ( iComponent * totalDofsPresent + dof().localToGlobalMap (elemId, 0) );
2123 
2124  // At each face loop on all the d.o.f.
2125  for (UInt iter_dof (0); iter_dof < nDof ; ++iter_dof)
2126  {
2127  // Map between local d.o.f. and global d.o.f.
2128  const ID globalDofID ( OriginalSpace.dof().localToGlobalMap ( elemId, iter_dof) );
2129 
2130  // Find the correct position in the final vector.
2131  const UInt iGlobalFacet ( mesh()->localFacetId ( elemId, iter_dof ) );
2132 
2133  // Select if the current facet is coherent or not with the orientation. If yes use +, if not use -.
2134  if ( mesh()->facet ( iGlobalFacet ).firstAdjacentElementIdentity() != iElem )
2135  {
2136  // Loop on each component of the selected finite element.
2137  for (UInt jComponent (0); jComponent < FieldDim; ++jComponent)
2138  {
2139  value -= OriginalVector[globalDofID] * Jac[jComponent] *
2140  OriginalSpace.refFE().phi (iter_dof, jComponent, barRefFE[0], barRefFE[1], barRefFE[2]);
2141  }
2142  }
2143  else
2144  {
2145  // Loop on each component of the selected finite element.
2146  for (UInt jComponent (0); jComponent < FieldDim; ++jComponent)
2147  {
2148  value += OriginalVector[globalDofID] * Jac[jComponent] *
2149  OriginalSpace.refFE().phi (iter_dof, jComponent, barRefFE[0], barRefFE[1], barRefFE[2]);
2150  }
2151  }
2152  }
2153 
2154  // Insert the final value.
2155  Interpolated[iGlobalFacePresent] = value / det;
2156  }
2157  }
2158 
2159  return Interpolated;
2160 }
2161 
2162 
2163 template<typename MeshType, typename MapType>
2164 UInt
2165 FESpace<MeshType, MapType>::
2166 polynomialDegree() const
2167 {
2168  switch (M_refFE->type() )
2169  {
2170  case FE_P0_0D:
2171  case FE_P0_2D:
2172  case FE_Q0_2D:
2173  case FE_P0_3D:
2174  case FE_Q0_3D:
2175  return 0;
2176  break;
2177 
2178  case FE_P1_1D:
2179  case FE_P1_2D:
2180  case FE_Q1_2D:
2181  case FE_P1_3D:
2182  case FE_Q1_3D:
2183  return 1;
2184  break;
2185 
2186  case FE_P2_1D:
2187  case FE_P2_2D:
2188  case FE_Q2_2D:
2189  case FE_P2_3D:
2190  case FE_Q2_3D:
2191  return 2;
2192  break;
2193 
2194  case FE_P1bubble_2D:
2195  return 3;
2196  break;
2197 
2198  case FE_P1bubble_3D:
2199  case FE_P2tilde_3D:
2200  return 4;
2201  break;
2202 
2203  default:
2204  std::cerr << " FESpace: No polynomial degre for this type of finite element " << std::endl;
2205  std::cerr << " FESpace: " << M_refFE->name() << std::endl;
2206  abort();
2207  };
2208 
2209  return 0;
2210 }
2211 
2212 } // end of the namespace
2213 #endif
VectorEpetra - The Epetra Vector format Wrapper.
const Real & weight(const UInt &ig) const
weight(ig) is the ig-th quadrature weight
bcType_Type type() const
Returns the boundary condition type.
Definition: BCBase.cpp:717
const Real & y() const
Recovering the node&#39;s y-coordinate.
const flag_Type UPDATE_DPHI(UPDATE_ONLY_CELL_NODES|UPDATE_ONLY_DPHI_GEO_MAP|UPDATE_ONLY_JACOBIAN|UPDATE_ONLY_T_INVERSE_JACOBIAN|UPDATE_ONLY_DPHI_REF|UPDATE_ONLY_DPHI|UPDATE_ONLY_DET_JACOBIAN)
const Real & z() const
Recovering the node&#39;s z-coordinate.
A class for a finite element on a manifold.
BCHandler - class for handling boundary conditions.
Definition: BCHandler.hpp:100
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
const FE_TYPE & type() const
Getter for the type of the finite element.
bool hasBoundaryFE() const
Check if the reference element has boundary elements.
BCBase & operator[](const ID &)
Extract a BC in the list.
Definition: BCHandler.cpp:92
void updateInverseJacobian(const UInt &iQuadPt)
const flag_Type UPDATE_WDET(UPDATE_ONLY_CELL_NODES|UPDATE_ONLY_DPHI_GEO_MAP|UPDATE_ONLY_JACOBIAN|UPDATE_ONLY_DET_JACOBIAN|UPDATE_ONLY_W_DET_JACOBIAN)
Real operator()(const Real &t, const Real &x, const Real &y, const Real &z, const ID &iComponent) const
Overloading function operator by calling the BCFunctionBase user specified function.
Definition: BCBase.cpp:645
UInt numberOfComponents() const
Returns the number of components involved in this boundary condition.
Definition: BCBase.cpp:727
#define ERROR_MSG(A)
Definition: LifeAssert.hpp:69
Real dphi(UInt node, UInt derivative, UInt quadNode) const
Getter for the derivatives of the basis functions.
Definition: CurrentFE.hpp:486
#define ASSERT_PRE(X, A)
Definition: LifeAssert.hpp:96
Real & operator[](UInt const &i)
Operator [].
#define ASSERT(X, A)
Definition: LifeAssert.hpp:90
uint32_type ID
IDs.
Definition: LifeV.hpp:194
virtual Real measure() const
Return the measure of the current element.
Definition: CurrentFE.cpp:563
Real elementaryFctL2NormSquare(std::function< Real(Real, Real, Real) > fct, const CurrentFE &fe)
returns the square of the L2 norm of fct on the current element
Real quadNode(UInt node, UInt coordinate) const
Getter for the quadrature nodes.
Definition: CurrentFE.hpp:444
double Real
Generic real data.
Definition: LifeV.hpp:175
CurrentFE - A primordial class for the assembly of the local matrices/vectors retaining the values on...
Definition: CurrentFE.hpp:243
The class for a reference Lagrangian finite element.
const BCIdentifierBase * operator[](const ID &i) const
Returns a pointer to the (i)-th element of the list of identifiers.
Definition: BCBase.cpp:638
const ID & id() const
Returns the ID of the BCIdentifier.
const flag_Type UPDATE_QUAD_NODES(UPDATE_ONLY_CELL_NODES|UPDATE_ONLY_QUAD_NODES)
BCIdentifierEssential - BCIdentifier for implementing Essential Boundary Conditions.
const Real & x() const
Recovering the node&#39;s x-coordinate.
#define LIFEV_DEPRECATED(func)
Definition: LifeV.hpp:117
bool bcUpdateDone() const
Determine whether bcUpdate has been done before.
Definition: BCHandler.hpp:502
VectorSmall< 3 > Vector3D
ID component(const ID i) const
Returns the index of the component of the solution associated to the iComponent-th component prescrib...
Definition: BCBase.cpp:466
UInt size() const
Number of the stored boundary conditions.
Definition: BCHandler.hpp:482
QuadratureRule - The basis class for storing and accessing quadrature rules.
UInt list_size() const
Returns the size of the identifiers list.
Definition: BCBase.cpp:551
const UInt & nbQuadPt() const
Getter for the number of quadrature points.
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191