LifeV
ADRAssemblerIP.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 File containing the IP stabilization for the ADR problem.
30 
31  @author Samuel Quinodoz <samuel.quinodoz@epfl.ch>
32  @date 06-10-2010
33 
34  @contributor Samuel Quinodoz <samuel.quinodoz@epfl.ch>
35  @mantainer Samuel Quinodoz <samuel.quinodoz@epfl.ch>
36 
37  A more detailed description of the file (if necessary)
38  */
39 
40 #ifndef ADRASSEMBLERIP_H
41 #define ADRASSEMBLERIP_H 1
42 
43 
44 #include <boost/scoped_ptr.hpp>
45 
46 
47 #include <lifev/core/LifeV.hpp>
48 
49 #include <lifev/core/util/LifeChrono.hpp>
50 
51 #include <lifev/core/fem/Assembly.hpp>
52 #include <lifev/core/fem/FESpace.hpp>
53 #include <lifev/core/fem/AssemblyElemental.hpp>
54 
55 namespace LifeV
56 {
57 
58 //! ADRAssemblerIP - This class is used to add IP stabilization to an Advection-Diffusion-Reaction problem.
59 /*!
60 
61  <b> Scope </b>
62 
63  This is class has been designed to add the IP stabilization for the ADR problem (see in the ADRAssembler class
64  for more detail about that problem). IP stands for Interior Penalty. Indeed, the idea of this stabililization
65  is to penalize the solutions that would exhibit oscillations. To quantify the smoothness of the solution, one
66  can rely on the computation of the jump of gradient across the faces:
67 
68  \f[ \sum_K \sum_{F \subset K} \int_F [\![ \nabla u ]\!] [\![ \nabla v ]\!] \f]
69 
70  where K represents an element and F one of its faces. The IP stabilization consists then in adding
71  the new bilinear form
72 
73  \f[ \sum_K \sum_{F \subset K} \int_F k [\![ \nabla u ]\!] [\![ \nabla v ]\!] \f]
74 
75  in the formulation of the ADR problem to force the solution to be smooth. The coefficient \f$ k \f$
76  is used to control the strength of the penalization as well as the good convergence behaviour of the
77  stabilized scheme.
78 
79  In this class, two choices are possible for \f$ k \f$
80 
81  <ul>
82  <li> Usually, the choice is \f$ k = \gamma h_F^2 \f$ to ensure the near-optimal convergence of the scheme, \f$ \gamma \f$
83  being a fixed parameter.
84 
85  <li> For advection dominated flows, it might be easier to use the formula \f$ k = \gamma |\beta \cdot n_F| h_F^2 \f$.
86  The choice for a suitable constant \f$ \gamma \f$ does not depend then on the magnitude of the field \f$ \beta \f$ and
87  the penalization is somehow better balanced in the domain.
88  </ul>
89 
90  <b> Stencil problems </b>
91 
92  One of the issues of the IP stabilization is the enlargement of the stencil with respect to the standard
93  Galerkin approximation. Indeed, the IP stabilization couples that would not be coupled otherwise: if we
94  consider a given face F, all the degrees of freedom of the two adjacent elements are coupled together, including
95  degrees of freedom that do not belong to a common element.
96 
97  From the computational point of view, this can sometimes be not acceptable: the enlarged stencil increases the
98  size of the matrix and (often) the size of the preconditioner (and so the time to compute it). For example, if
99  the LU factorization of matrix is computed, the factors will have much more non-zero entries because the new
100  entries in the matrix are usually "far" from the diagonal.
101 
102  To eleviate this problem in some situation, this class provides the possibility to assemble the stabilization
103  in two different matrices:
104  <ul>
105  <li> In one of the matrices (matrixGalerkin), the terms concerning basis functions that belong to the same element are added
106  <li> In the other matrice (matrixExtended), the terms concerning basis functions that do not belong to the same element
107  are added.
108  </ul>
109 
110  This allows to use the first matrix in the system and try to explicit the term corresponding to the second matrix
111  (putting it in the right hand side). For example, when dealing with parabolic ADR problems,
112  one can use the solution of the previous time step (or an extrapolation of the solution)
113  to explicit the stabilization by adding in the right hand side the
114  product of the extended matrix with the approximated solution.
115 
116  <b> Use </b>
117 
118  There are two main kind of method: setup methods and stabilization assembly methods.
119 
120  The setup method is used to simply build the few internal data structures that are needed for the assembly.
121  One should always start by setting up the FESpaces needed.
122 
123  Once this is done, the assembly can be performed. There are here 4 methods, distinguished by 2 options.
124 
125  The first option is whether the scaling of the stabilization should depend on the
126  advection field. If one wants to have a scaling \f$ |\beta \cdot n| \f$ in front of the
127  stabilization, then \beta has to appear in the arguments of the function.
128 
129  The second option (more advanced) is whether all the terms of the stabilization have to
130  be added to the same matrix. If one want to handle the stencil problem, then two
131  distinct matrices have to be passed to the methods.
132 
133  @author Samuel Quinodoz
134 
135  @remark: no choice for the quadrature here, because of currentBDFE.
136  */
137 
138 template< typename mesh_type, typename matrix_type, typename vector_type>
139 class ADRAssemblerIP
140 {
141 public:
142 
143  //! @name Public Types
144  //@{
145 
146  typedef MapEpetra map_Type;
147 
148  typedef FESpace<mesh_type, map_Type> fespace_type;
149  typedef std::shared_ptr<fespace_type> fespace_ptrType;
150 
151  typedef std::shared_ptr<matrix_type> matrix_ptrType;
152 
153  //@}
154 
155 
156  //! @name Constructor & Destructor
157  //@{
158 
159  //! Empty Constructor
160  ADRAssemblerIP();
161 
162  //! Destructor
163  ~ADRAssemblerIP() {};
164 
165  //@}
166 
167 
168 
169  //! @name Methods
170  //@{
171 
172  //! Setup method for the FESpaces
173  void setup ( const fespace_ptrType& fespace, const fespace_ptrType& betaFEspace);
174 
175  //! This method adds the IP stabilization terms into two matrices depending on the stencil.
176  /*!
177  This method is the main method of this class. It adds the IP stabilization terms into
178  two matrices, matrixGalerkin and matrixExtended. In the matrix Galerkin, the terms
179  for the terms of the Galerkin stencil are added. In the matrix Extended, the terms
180  for the eventually extra stencil are added. Beta is the transport field (given for the
181  betaFESpace), coef is a coefficient that is put in front of all the terms.
182  */
183  void addIPStabilizationStencil (const matrix_ptrType& matrixGalerkin,
184  const matrix_ptrType& matrixExtended,
185  const vector_type& beta,
186  const Real& coef);
187 
188  //! This method adds the IP stabilization on the two matrices, depening on the stencil.
189  /*!
190  However, it does not take into account the advection field to balance the stabilization.
191  */
192  void addIPStabilizationStencil (const matrix_ptrType& matrixGalerkin,
193  const matrix_ptrType& matrixExtended,
194  const Real& coef);
195 
196  //! This method builds the IP stabilization on a unique matrix (both stencils)
197  /*!
198  This method takes also into account the transport field for wieghting the
199  stabilization.
200  */
201  void addIPStabilization (const matrix_ptrType& matrix,
202  const vector_type& beta,
203  const Real& coef)
204  {
205  addIPStabilizationStencil (matrix, matrix, beta, coef);
206  }
207 
208  //! Simplest method to add IP stabilization on the matrix.
209  /*!
210  Terms for both stencils are added on the same matrix and the coefficient
211  acts uniformly on the domain (no scaling with the transport field)
212  */
213  void addIPStabilization (const matrix_ptrType& matrix,
214  const Real& coef)
215  {
216  addIPStabilizationStencil (matrix, matrix, coef);
217  }
218 
219  //@}
220 
221 private:
222 
223  typedef MatrixElemental localMatrix_type;
224  typedef std::unique_ptr<localMatrix_type> localMatrix_ptrType;
225 
226  typedef CurrentFE currentFE_type;
227  typedef std::unique_ptr<currentFE_type> currentFE_ptrType;
228 
229  typedef CurrentFEManifold currentBdFE_type;
230  typedef std::unique_ptr<currentBdFE_type> currentBdFE_ptrType;
231 
232 
233  // Finite element space for the unknown
234  fespace_ptrType M_fespace;
235 
236  // Finite element space for the advection
237  fespace_ptrType M_betaFESpace;
238 
239  currentBdFE_ptrType M_IPFaceCFE;
240 
241  currentFE_ptrType M_IPQuad1CFE;
242  currentFE_ptrType M_IPQuad2CFE;
243 
244  currentFE_ptrType M_IP1CFE;
245  currentFE_ptrType M_IP2CFE;
246 
247  currentFE_ptrType M_IPBetaCFE;
248 
249  // local matrix for the Galerkin stencil entries
250  localMatrix_ptrType M_localIPGalerkin_11;
251  localMatrix_ptrType M_localIPGalerkin_22;
252 
253  // local matrix for the Extended stencil entries
254  localMatrix_ptrType M_localIPExtended_12;
255  localMatrix_ptrType M_localIPExtended_21;
256 };
257 
258 // ===================================================
259 // Constructors & Destructor
260 // ===================================================
261 
262 template<typename mesh_type, typename matrix_type, typename vector_type>
263 ADRAssemblerIP< mesh_type, matrix_type, vector_type>::
264 ADRAssemblerIP() :
265 
266  M_fespace(),
267  M_betaFESpace(),
268 
269  M_IPFaceCFE(),
270 
271  M_IPQuad1CFE(),
272  M_IPQuad2CFE(),
273 
274  M_IP1CFE(),
275  M_IP2CFE(),
276 
277  M_IPBetaCFE(),
278 
279  M_localIPGalerkin_11(),
280  M_localIPGalerkin_22(),
281  M_localIPExtended_12(),
282  M_localIPExtended_21()
283 {}
284 
285 // ===================================================
286 // Methods
287 // ===================================================
288 
289 template<typename mesh_type, typename matrix_type, typename vector_type>
290 void
291 ADRAssemblerIP< mesh_type, matrix_type, vector_type>::
292 setup ( const fespace_ptrType& fespace, const fespace_ptrType& betaFESpace )
293 {
294  M_fespace = fespace;
295  M_betaFESpace = betaFESpace;
296 
297  M_IPFaceCFE.reset (new CurrentFEManifold (M_fespace->feBd().refFE(), M_fespace->feBd().geoMap(), M_fespace->feBd().quadRule() ) );
298 
299  // For the two next CurrentFEs, the quadrature plays no role
300  M_IPQuad1CFE.reset (new CurrentFE (M_fespace->refFE(), M_fespace->fe().geoMap(), M_fespace->qr() ) );
301  M_IPQuad2CFE.reset (new CurrentFE (M_fespace->refFE(), M_fespace->fe().geoMap(), M_fespace->qr() ) );
302 
303  // For the three next CurrentFEs, the quadrature will be replaced when computing the
304  // IP stabilization
305  M_IP1CFE.reset (new CurrentFE (M_fespace->refFE(), M_fespace->fe().geoMap(), M_fespace->qr() ) );
306  M_IP2CFE.reset (new CurrentFE (M_fespace->refFE(), M_fespace->fe().geoMap(), M_fespace->qr() ) );
307  M_IPBetaCFE.reset (new CurrentFE (M_betaFESpace->refFE(), M_fespace->fe().geoMap(), M_fespace->qr() ) );
308 
309  // Local matrices
310  M_localIPGalerkin_11.reset (new localMatrix_type (M_fespace->fe().nbFEDof()
311  , M_fespace->fieldDim()
312  , M_fespace->fieldDim() ) );
313  M_localIPGalerkin_22.reset (new localMatrix_type (M_fespace->fe().nbFEDof()
314  , M_fespace->fieldDim()
315  , M_fespace->fieldDim() ) );
316  M_localIPExtended_12.reset (new localMatrix_type (M_fespace->fe().nbFEDof()
317  , M_fespace->fieldDim()
318  , M_fespace->fieldDim() ) );
319  M_localIPExtended_21.reset (new localMatrix_type (M_fespace->fe().nbFEDof()
320  , M_fespace->fieldDim()
321  , M_fespace->fieldDim() ) );
322 }
323 
324 template<typename mesh_type, typename matrix_type, typename vector_type>
325 void
326 ADRAssemblerIP< mesh_type, matrix_type, vector_type>::
327 addIPStabilizationStencil (const matrix_ptrType& matrixGalerkin,
328  const matrix_ptrType& matrixExtended,
329  const vector_type& beta,
330  const Real& coef)
331 {
332  if (beta.mapType() != Repeated)
333  {
334  addIPStabilizationStencil (matrixGalerkin, matrixExtended, vector_type (beta, Repeated), coef);
335  return;
336  }
337 
338  ASSERT (M_fespace != 0, "No FE space for building the IP stabilization! ");
339  ASSERT (M_betaFESpace != 0, "No FE space (beta) for building the IP stabilization! ");
340 
341  // Some constants
342  const UInt nbBoundaryFaces (M_fespace->mesh()->numBFaces() );
343  const UInt nbFaces (M_fespace->mesh()->numFaces() );
344  const UInt nbQuadPt (M_fespace->bdQr().nbQuadPt() );
345  const UInt nbLocalDof (M_fespace->fe().nbFEDof() );
346  const UInt nbLocalBetaDof (M_betaFESpace->fe().nbFEDof() );
347  const UInt nbComponents (M_fespace->fieldDim() );
348  const UInt betaTotalDof (M_betaFESpace->dof().numTotalDof() );
349 
350 
351  // Temporaries
352  Real localValue_11 (0.0);
353  Real localValue_22 (0.0);
354  Real localValue_12 (0.0);
355  Real localValue_21 (0.0);
356  std::vector<Real> betaN (nbQuadPt, 0.0);
357  Real hFace2 (0.0);
358 
359  // Here instead of looping over the elements, we loop on the faces.
360  for (UInt iFace (nbBoundaryFaces); iFace < nbFaces; ++iFace)
361  {
362  // Get the adjacent elements ID
363  const UInt adjacentElement1 (M_fespace->mesh()->face (iFace).firstAdjacentElementIdentity() );
364  const UInt adjacentElement2 (M_fespace->mesh()->face (iFace).secondAdjacentElementIdentity() );
365 
366  // Here we check that the face is included in the IP
367  // stabilization: it is not a boundary face (we do not
368  // stabilize there). We also cannot (not possible) stabilize
369  // across the different partitions of the mesh (if they exist).
370  // These cases are the excluded.
371 
372  if ( Flag::testOneSet ( M_fespace->mesh()->face (iFace).flag(), EntityFlags::SUBDOMAIN_INTERFACE | EntityFlags::PHYSICAL_BOUNDARY ) )
373  {
374  continue;
375  };
376 
377  // Now the point is that we need to integrate on the face informations coming
378  // from the element (beta is defined on the volume, dphi as well). Therefore,
379  // we need to update the currentFEs with a quadrature that lies on the face.
380  // First step , we compute this quadrature.
381 
382  M_IPFaceCFE->update (M_fespace->mesh()->face (iFace), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS | UPDATE_QUAD_NODES);
383  hFace2 = M_IPFaceCFE->measure();
384 
385  // Second step, we take the quadrature back to the reference frame for both
386  // adjacent elements
387 
388  M_IPQuad1CFE->update ( M_fespace->mesh()->element (adjacentElement1), UPDATE_ONLY_CELL_NODES );
389 
390  QuadratureRule faceQR1 ("custom quad 1", TETRA, 3, 0, 0);
391  for (UInt iQuad (0); iQuad < nbQuadPt; ++iQuad) // Here we do not use UInt because of KNM, but we should
392  {
393  Real x (0.0), y (0.0), z (0.0);
394  M_IPQuad1CFE->coorBackMap ( M_IPFaceCFE->quadPt (iQuad, 0),
395  M_IPFaceCFE->quadPt (iQuad, 1),
396  M_IPFaceCFE->quadPt (iQuad, 2),
397  x, y, z);
398  QuadraturePoint newPoint (x, y, z, M_fespace->bdQr().weight (iQuad) );
399  faceQR1.addPoint (newPoint);
400  }
401 
402  M_IPQuad2CFE->update ( M_fespace->mesh()->element (adjacentElement2), UPDATE_ONLY_CELL_NODES );
403  QuadratureRule faceQR2 ("custom quad 2", TETRA, 3, 0, 0);
404  for (UInt iQuad (0); iQuad < nbQuadPt; ++iQuad) // Idem here
405  {
406  Real x (0.0), y (0.0), z (0.0);
407  M_IPQuad2CFE->coorBackMap ( M_IPFaceCFE->quadPt (iQuad, 0),
408  M_IPFaceCFE->quadPt (iQuad, 1),
409  M_IPFaceCFE->quadPt (iQuad, 2),
410  x, y, z);
411  QuadraturePoint newPoint (x, y, z, M_fespace->bdQr().weight (iQuad) );
412  faceQR2.addPoint (newPoint);
413  }
414 
415  // Third step, we change the quadrature in the CurrentFEs
416 
417  M_IP1CFE->setQuadRule (faceQR1);
418  M_IP2CFE->setQuadRule (faceQR2);
419  M_IPBetaCFE->setQuadRule (faceQR1);
420 
421  // Now the CurrentFEs are updated with a quadrature that is
422  // actually only on the considered face (iterFace).
423 
424  M_IP1CFE->update (M_fespace->mesh()->element (adjacentElement1), UPDATE_DPHI | UPDATE_WDET);
425  M_IP2CFE->update (M_fespace->mesh()->element (adjacentElement2), UPDATE_DPHI | UPDATE_WDET);
426 
427  // Before starting the assembly, we compute the values of |beta n|
428  // in the quadrature nodes
429 
430  for (UInt iQuadPt (0); iQuadPt < nbQuadPt; ++iQuadPt)
431  {
432  betaN[iQuadPt] = 0.0;
433  for (UInt iDof (0); iDof < nbLocalBetaDof; ++iDof)
434  {
435  for (UInt iDim (0); iDim < 3; ++iDim)
436  {
437  betaN[iQuadPt] += beta[M_betaFESpace->dof().localToGlobalMap (adjacentElement1, iDof)
438  + betaTotalDof * iDim]
439  * M_IPBetaCFE->phi (iDof, iQuadPt)
440  * M_IPFaceCFE->normal (iDim, iQuadPt);
441  }
442  }
443  betaN[iQuadPt] = std::fabs (betaN[iQuadPt]);
444  }
445 
446  // Now we can start the assembly. There are 4 parts, depending on
447  // which sides we consider ( side1 with side1, side1 with side2,...)
448  // We have also to be carefull about the signs, because we want the jumps
449  // Therefore, there is a "-" when considering two different sides.
450 
451  // Zero out the local matrices
452  M_localIPGalerkin_11->zero();
453  M_localIPGalerkin_22->zero();
454  M_localIPExtended_12->zero();
455  M_localIPExtended_21->zero();
456 
457  // Loop on the components
458  for (UInt iFieldDim (0); iFieldDim < nbComponents; ++iFieldDim)
459  {
460  // Extract the views
461  localMatrix_type::matrix_view viewIPGalerkin_11 = M_localIPGalerkin_11->block (iFieldDim, iFieldDim);
462  localMatrix_type::matrix_view viewIPGalerkin_22 = M_localIPGalerkin_22->block (iFieldDim, iFieldDim);
463  localMatrix_type::matrix_view viewIPExtended_12 = M_localIPExtended_12->block (iFieldDim, iFieldDim);
464  localMatrix_type::matrix_view viewIPExtended_21 = M_localIPExtended_21->block (iFieldDim, iFieldDim);
465 
466  for (UInt iDof (0); iDof < nbLocalDof; ++iDof)
467  {
468  for (UInt jDof (0); jDof < nbLocalDof; ++jDof)
469  {
470  localValue_11 = 0.0;
471  localValue_22 = 0.0;
472  localValue_12 = 0.0;
473  localValue_21 = 0.0;
474 
475  for (UInt iQuadPt (0); iQuadPt < nbQuadPt; ++iQuadPt)
476  {
477  for (UInt iDim (0); iDim < 3; ++iDim)
478  {
479  localValue_11 += betaN[iQuadPt]
480  * M_IP1CFE->dphi (iDof, iDim, iQuadPt)
481  * M_IP1CFE->dphi (jDof, iDim, iQuadPt)
482  * M_IP1CFE->wDetJacobian (iQuadPt);
483 
484  localValue_22 += betaN[iQuadPt]
485  * M_IP2CFE->dphi (iDof, iDim, iQuadPt)
486  * M_IP2CFE->dphi (jDof, iDim, iQuadPt)
487  * M_IP2CFE->wDetJacobian (iQuadPt);
488 
489  localValue_12 += betaN[iQuadPt]
490  * M_IP1CFE->dphi (iDof, iDim, iQuadPt)
491  * M_IP2CFE->dphi (jDof, iDim, iQuadPt)
492  * M_IP1CFE->wDetJacobian (iQuadPt);
493 
494  localValue_21 += betaN[iQuadPt]
495  * M_IP2CFE->dphi (iDof, iDim, iQuadPt)
496  * M_IP1CFE->dphi (jDof, iDim, iQuadPt)
497  * M_IP1CFE->wDetJacobian (iQuadPt);
498  }
499  }
500 
501  // Here we put the values in the local matrices
502  // We care for sign (to get jumps) and for the
503  // coefficient here.
504  viewIPGalerkin_11 (iDof, jDof) += coef * hFace2 * localValue_11;
505  viewIPGalerkin_22 (iDof, jDof) += coef * hFace2 * localValue_22;
506  viewIPExtended_12 (iDof, jDof) += -coef * hFace2 * localValue_12;
507  viewIPExtended_21 (iDof, jDof) += -coef * hFace2 * localValue_21;
508  }
509  }
510  }
511 
512  // Global Assembly
513  // We separate here the assembly of the two
514  // contributions for Galerkin and Extended
515  // stencil.
516 
517  for (UInt iFieldDim (0); iFieldDim < nbComponents; ++iFieldDim)
518  {
519  assembleMatrix ( *matrixGalerkin,
520  *M_localIPGalerkin_11,
521  *M_IP1CFE,
522  *M_IP1CFE,
523  M_fespace->dof(),
524  M_fespace->dof(),
525  iFieldDim, iFieldDim,
526  iFieldDim * M_fespace->dof().numTotalDof(), iFieldDim * M_fespace->dof().numTotalDof() );
527 
528  assembleMatrix ( *matrixGalerkin,
529  *M_localIPGalerkin_22,
530  *M_IP2CFE,
531  *M_IP2CFE,
532  M_fespace->dof(),
533  M_fespace->dof(),
534  iFieldDim, iFieldDim,
535  iFieldDim * M_fespace->dof().numTotalDof(), iFieldDim * M_fespace->dof().numTotalDof() );
536 
537  assembleMatrix ( *matrixExtended,
538  *M_localIPExtended_12,
539  *M_IP1CFE,
540  *M_IP2CFE,
541  M_fespace->dof(),
542  M_fespace->dof(),
543  iFieldDim, iFieldDim,
544  iFieldDim * M_fespace->dof().numTotalDof(), iFieldDim * M_fespace->dof().numTotalDof() );
545 
546  assembleMatrix ( *matrixExtended,
547  *M_localIPExtended_21,
548  *M_IP2CFE,
549  *M_IP1CFE,
550  M_fespace->dof(),
551  M_fespace->dof(),
552  iFieldDim, iFieldDim,
553  iFieldDim * M_fespace->dof().numTotalDof(), iFieldDim * M_fespace->dof().numTotalDof() );
554  }
555  }
556 
557 }
558 
559 template<typename mesh_type, typename matrix_type, typename vector_type>
560 void
561 ADRAssemblerIP< mesh_type, matrix_type, vector_type>::
562 addIPStabilizationStencil (const matrix_ptrType& matrixGalerkin,
563  const matrix_ptrType& matrixExtended,
564  const Real& coef)
565 {
566  ASSERT (M_fespace != 0, "No FE space for building the IP stabilization! ");
567 
568  // Some constants
569  const UInt nbBoundaryFaces (M_fespace->mesh()->numBFaces() );
570  const UInt nbFaces (M_fespace->mesh()->numFaces() );
571  const UInt nbQuadPt (M_fespace->bdQr().nbQuadPt() );
572  const UInt nbLocalDof (M_fespace->fe().nbFEDof() );
573  const UInt nbComponents (M_fespace->fieldDim() );
574 
575 
576  // Temporaries
577  Real localValue_11 (0.0);
578  Real localValue_22 (0.0);
579  Real localValue_12 (0.0);
580  Real localValue_21 (0.0);
581  Real hFace2 (0.0);
582 
583  // Here instead of looping over the elements, we loop on the faces.
584  for (UInt iFace (nbBoundaryFaces); iFace < nbFaces; ++iFace)
585  {
586  // Get the adjacent elements ID
587  const UInt adjacentElement1 (M_fespace->mesh()->face (iFace).firstAdjacentElementIdentity() );
588  const UInt adjacentElement2 (M_fespace->mesh()->face (iFace).secondAdjacentElementIdentity() );
589 
590  // Here we check that the face is included in the IP
591  // stabilization: it is not a boundary face (we do not
592  // stabilize there). We also cannot (not possible) stabilize
593  // across the different partitions of the mesh (if they exist).
594  // These cases are the excluded.
595 
596  if ( (adjacentElement1 == NotAnId) || (adjacentElement2 == NotAnId) || (adjacentElement1 == adjacentElement2) )
597  {
598  continue;
599  };
600 
601  // Now the point is that we need to integrate on the face informations coming
602  // from the element (beta is defined on the volume, dphi as well). Therefore,
603  // we need to update the currentFEs with a quadrature that lies on the face.
604  // First step , we compute this quadrature.
605 
606  M_IPFaceCFE->update (M_fespace->mesh()->face (iFace), UPDATE_W_ROOT_DET_METRIC | UPDATE_QUAD_NODES);
607  hFace2 = M_IPFaceCFE->measure();
608 
609  // Second step, we take the quadrature back to the reference frame for both
610  // adjacent elements
611 
612  M_IPQuad1CFE->update ( M_fespace->mesh()->element (adjacentElement1), UPDATE_ONLY_CELL_NODES );
613 
614  QuadratureRule faceQR1 ("custom quad 1", TETRA, 3, 0, 0);
615  for (int iQuad (0); iQuad < nbQuadPt; ++iQuad) // Here we do not use UInt because of KNM, but we should
616  {
617  Real x (0.0), y (0.0), z (0.0);
618  M_IPQuad1CFE->coorBackMap ( M_IPFaceCFE->quadPt (iQuad, 0),
619  M_IPFaceCFE->quadPt (iQuad, 1),
620  M_IPFaceCFE->quadPt (iQuad, 2),
621  x, y, z);
622  QuadraturePoint newPoint (x, y, z, M_fespace->bdQr().weight (iQuad) );
623  faceQR1.addPoint (newPoint);
624  }
625 
626  M_IPQuad2CFE->update ( M_fespace->mesh()->element (adjacentElement2), UPDATE_ONLY_CELL_NODES );
627  QuadratureRule faceQR2 ("custom quad 2", TETRA, 3, 0, 0);
628  for (int iQuad (0); iQuad < nbQuadPt; ++iQuad) // Idem here
629  {
630  Real x (0.0), y (0.0), z (0.0);
631  M_IPQuad2CFE->coorBackMap ( M_IPFaceCFE->quadPt (iQuad, 0),
632  M_IPFaceCFE->quadPt (iQuad, 1),
633  M_IPFaceCFE->quadPt (iQuad, 2),
634  x, y, z);
635  QuadraturePoint newPoint (x, y, z, M_fespace->bdQr().weight (iQuad) );
636  faceQR2.addPoint (newPoint);
637  }
638 
639  // Third step, we change the quadrature in the CurrentFEs
640 
641  M_IP1CFE->setQuadRule (faceQR1);
642  M_IP2CFE->setQuadRule (faceQR2);
643 
644  // Now the CurrentFEs are updated with a quadrature that is
645  // actually only on the considered face (iterFace).
646 
647  M_IP1CFE->update (M_fespace->mesh()->element (adjacentElement1), UPDATE_DPHI | UPDATE_WDET);
648  M_IP2CFE->update (M_fespace->mesh()->element (adjacentElement2), UPDATE_DPHI | UPDATE_WDET);
649 
650  // Now we can start the assembly. There are 4 parts, depending on
651  // which sides we consider ( side1 with side1, side1 with side2,...)
652  // We have also to be carefull about the signs, because we want the jumps
653  // Therefore, there is a "-" when considering two different sides.
654 
655  // Zero out the local matrices
656  M_localIPGalerkin_11->zero();
657  M_localIPGalerkin_22->zero();
658  M_localIPExtended_12->zero();
659  M_localIPExtended_21->zero();
660 
661  // Loop on the components
662  for (UInt iFieldDim (0); iFieldDim < nbComponents; ++iFieldDim)
663  {
664  // Extract the views
665  localMatrix_type::matrix_view viewIPGalerkin_11 = M_localIPGalerkin_11->block (iFieldDim, iFieldDim);
666  localMatrix_type::matrix_view viewIPGalerkin_22 = M_localIPGalerkin_22->block (iFieldDim, iFieldDim);
667  localMatrix_type::matrix_view viewIPExtended_12 = M_localIPExtended_12->block (iFieldDim, iFieldDim);
668  localMatrix_type::matrix_view viewIPExtended_21 = M_localIPExtended_21->block (iFieldDim, iFieldDim);
669 
670  for (UInt iDof (0); iDof < nbLocalDof; ++iDof)
671  {
672  for (UInt jDof (0); jDof < nbLocalDof; ++jDof)
673  {
674  localValue_11 = 0.0;
675  localValue_22 = 0.0;
676  localValue_12 = 0.0;
677  localValue_21 = 0.0;
678 
679  for (UInt iQuadPt (0); iQuadPt < nbQuadPt; ++iQuadPt)
680  {
681  for (UInt iDim (0); iDim < 3; ++iDim)
682  {
683  localValue_11 += 1.0
684  * M_IP1CFE->dphi (iDof, iDim, iQuadPt)
685  * M_IP1CFE->dphi (jDof, iDim, iQuadPt)
686  * M_IP1CFE->wDetJacobian (iQuadPt);
687 
688  localValue_22 += 1.0
689  * M_IP2CFE->dphi (iDof, iDim, iQuadPt)
690  * M_IP2CFE->dphi (jDof, iDim, iQuadPt)
691  * M_IP2CFE->wDetJacobian (iQuadPt);
692 
693  localValue_12 += 1.0
694  * M_IP1CFE->dphi (iDof, iDim, iQuadPt)
695  * M_IP2CFE->dphi (jDof, iDim, iQuadPt)
696  * M_IP1CFE->wDetJacobian (iQuadPt);
697 
698  localValue_21 += 1.0
699  * M_IP2CFE->dphi (iDof, iDim, iQuadPt)
700  * M_IP1CFE->dphi (jDof, iDim, iQuadPt)
701  * M_IP1CFE->wDetJacobian (iQuadPt);
702  }
703  }
704 
705  // Here we put the values in the local matrices
706  // We care for sign (to get jumps) and for the
707  // coefficient here.
708  viewIPGalerkin_11 (iDof, jDof) += coef * hFace2 * localValue_11;
709  viewIPGalerkin_22 (iDof, jDof) += coef * hFace2 * localValue_22;
710  viewIPExtended_12 (iDof, jDof) += -coef * hFace2 * localValue_12;
711  viewIPExtended_21 (iDof, jDof) += -coef * hFace2 * localValue_21;
712  }
713  }
714  }
715 
716  // Global Assembly
717  // We separate here the assembly of the two
718  // contributions for Galerkin and Extended
719  // stencil.
720 
721  for (UInt iFieldDim (0); iFieldDim < nbComponents; ++iFieldDim)
722  {
723  assembleMatrix ( *matrixGalerkin,
724  *M_localIPGalerkin_11,
725  *M_IP1CFE,
726  *M_IP1CFE,
727  M_fespace->dof(),
728  M_fespace->dof(),
729  iFieldDim, iFieldDim,
730  iFieldDim * M_fespace->dof().numTotalDof(), iFieldDim * M_fespace->dof().numTotalDof() );
731 
732  assembleMatrix ( *matrixGalerkin,
733  *M_localIPGalerkin_22,
734  *M_IP2CFE,
735  *M_IP2CFE,
736  M_fespace->dof(),
737  M_fespace->dof(),
738  iFieldDim, iFieldDim,
739  iFieldDim * M_fespace->dof().numTotalDof(), iFieldDim * M_fespace->dof().numTotalDof() );
740 
741  assembleMatrix ( *matrixExtended,
742  *M_localIPExtended_12,
743  *M_IP1CFE,
744  *M_IP2CFE,
745  M_fespace->dof(),
746  M_fespace->dof(),
747  iFieldDim, iFieldDim,
748  iFieldDim * M_fespace->dof().numTotalDof(), iFieldDim * M_fespace->dof().numTotalDof() );
749 
750  assembleMatrix ( *matrixExtended,
751  *M_localIPExtended_21,
752  *M_IP2CFE,
753  *M_IP1CFE,
754  M_fespace->dof(),
755  M_fespace->dof(),
756  iFieldDim, iFieldDim,
757  iFieldDim * M_fespace->dof().numTotalDof(), iFieldDim * M_fespace->dof().numTotalDof() );
758  }
759  }
760 
761 }
762 
763 } // Namespace LifeV
764 
765 #endif /* ADRASSEMBLERIP_H */
A class for a finite element on a manifold.
Epetra_Import const & importer()
Getter for the Epetra_Import.
Definition: MapEpetra.cpp:394
#define ASSERT(X, A)
Definition: LifeAssert.hpp:90
QuadraturePoint - Simple container for a point of a quadrature rule.
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
const ID NotAnId
Definition: LifeV.hpp:264
QuadratureRule - The basis class for storing and accessing quadrature rules.
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191