LifeV
lifev/eta/tutorials/6_ETA_functor/main.cpp
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 Tutorial for the use of functor in the ETA framework
30 
31  @author Samuel Quinodoz <samuel.quinodoz@epfl.ch>
32  @date 08-10-2010
33 
34  In this tutorial, we show how the functors can be used
35  to add functionalities to the ETA framework.
36 
37  We show, in particular, how to assemble a SUPG stabilized
38  advection diffusion matrix. We also show how to integrate
39  functions without interpolating them.
40 
41  Tutorials that should be read before: 1,2,3
42  */
43 
44 // ---------------------------------------------------------------
45 // We include the same files as in the previous tutorial. No new
46 // file is required to use the functor functionalities, they are
47 // already contained in the Integrate.hpp file.
48 // ---------------------------------------------------------------
49 
50 
51 #include <Epetra_ConfigDefs.h>
52 #ifdef EPETRA_MPI
53 #include <mpi.h>
54 #include <Epetra_MpiComm.h>
55 #else
56 #include <Epetra_SerialComm.h>
57 #endif
58 
59 
60 #include <lifev/core/LifeV.hpp>
61 
62 #include <lifev/core/mesh/MeshPartitioner.hpp>
63 #include <lifev/core/mesh/RegionMesh3DStructured.hpp>
64 #include <lifev/core/mesh/RegionMesh.hpp>
65 
66 #include <lifev/core/array/MatrixEpetra.hpp>
67 #include <lifev/core/array/VectorEpetra.hpp>
68 
69 #include <lifev/eta/fem/ETFESpace.hpp>
70 #include <lifev/eta/expression/Integrate.hpp>
71 
72 #include <lifev/core/fem/FESpace.hpp>
73 
74 #include <boost/shared_ptr.hpp>
75 
76 // ---------------------------------------------------------------
77 // We work in the LifeV namespace and define the mesh, matrix and
78 // vector types that we will need several times.
79 // ---------------------------------------------------------------
80 
81 using namespace LifeV;
82 
84 typedef MatrixEpetra<Real> matrix_Type;
85 typedef VectorEpetra vector_Type;
86 typedef FESpace<mesh_Type, MapEpetra>::function_Type function_Type;
87 
88 
89 // ---------------------------------------------------------------
90 // We define here a function for the sake of comparison for the
91 // right hand side that we will consider.
92 // ---------------------------------------------------------------
93 
94 Real fFctRaw ( const Real& /* t */, const Real& x, const Real& /* y */, const Real& /* z */, const ID& /*i*/ )
95 {
96  return std::sin (x);
97 }
98 function_Type fFct (fFctRaw);
99 
100 // ---------------------------------------------------------------
101 // To use the functors, we need to define new classes, which are
102 // the functors. First of all, we define such a class that is
103 // equivalent to the fFct function that we have just defined.
104 // Several elements must be present in this class:
105 //
106 // - A type, called return_Type, which represents the type of
107 // the values returned by the class. If the evaluation of the
108 // function is supposed to be scalar, it is Real, if it is
109 // vectorial valued, the type is VectorSmall,... Here, the
110 // represented function is scalar, so we define it as Real.
111 //
112 // - An operator() function, which takes in argument the wanted
113 // type (with the same reasoning as the return_Type) and return
114 // a return_Type. Here, we want the functor to return the sinus
115 // of the first component of the position (which is a vectorial
116 // quantity).
117 //
118 // - The copy constructor and the destructor are mandatory as
119 // well (we explicit them here).
120 //
121 // The example that make in this tutorial are very simple, but a
122 // functor class can contain data, have much more methods,...
123 // There is no limitation, excepted the three requirements listed
124 // above.
125 // ---------------------------------------------------------------
126 
127 class fFunctor
128 {
129 public:
130  typedef Real return_Type;
131 
132  return_Type operator() (const VectorSmall<3>& position)
133  {
134  return std::sin ( position[0] );
135  }
136 
137  fFunctor() {}
138  fFunctor (const fFunctor&) {}
139  ~fFunctor() {}
140 };
141 
142 
143 // ---------------------------------------------------------------
144 // We want also to implement a SUPG stabilized advection diffusion
145 // problem. To weight the stabilization term, we would like to
146 // have an expression that computes the norm of the advection
147 // field. As there is no expression already set up for it, we
148 // devise a functor.
149 //
150 // For the sake of exposition, we add a member to the functor
151 // representing the exponent of the norm.
152 //
153 // Following the same rules as before, we define the following
154 // class.
155 // ---------------------------------------------------------------
156 
158 {
159 public:
160  typedef Real return_Type;
161 
162  return_Type operator() (const VectorSmall<3>& advection_field)
163  {
164  return std::pow ( std::pow ( std::abs (advection_field[0]), M_exponent)
165  + std::pow ( std::abs (advection_field[1]), M_exponent)
166  + std::pow ( std::abs (advection_field[2]), M_exponent)
167  , 1.0 / M_exponent);
168  }
169 
170  normFunctor (const UInt& expo = 1)
171  : M_exponent (expo) {}
172 
174  : M_exponent (nf.M_exponent) {}
175 
177 
178  void setExponent (const UInt& expo)
179  {
180  M_exponent = expo;
181  }
182 
183 private:
184 
186 };
187 
188 
189 // ---------------------------------------------------------------
190 // As usual, we start by the MPI communicator, the definition of
191 // the mesh and its partitioning
192 // ---------------------------------------------------------------
193 
194 int main ( int argc, char** argv )
195 {
196 
197 #ifdef HAVE_MPI
198  MPI_Init (&argc, &argv);
199  std::shared_ptr<Epetra_Comm> Comm (new Epetra_MpiComm (MPI_COMM_WORLD) );
200 #else
201  std::shared_ptr<Epetra_Comm> Comm (new Epetra_SerialComm);
202 #endif
203 
204  const bool verbose (Comm->MyPID() == 0);
205 
206 
207  if (verbose)
208  {
209  std::cout << " -- Building and partitioning the mesh ... " << std::flush;
210  }
211 
212  const UInt Nelements (10);
213 
214  std::shared_ptr< mesh_Type > fullMeshPtr (new mesh_Type ( Comm ) );
215 
216  regularMesh3D ( *fullMeshPtr, 1, Nelements, Nelements, Nelements, false,
217  2.0, 2.0, 2.0,
218  -1.0, -1.0, -1.0);
219 
220  std::shared_ptr< mesh_Type > meshPtr;
221  {
222  MeshPartitioner< mesh_Type > meshPart (fullMeshPtr, Comm);
223  meshPtr = meshPart.meshPartition();
224  }
225 
226  fullMeshPtr.reset();
227 
228  if (verbose)
229  {
230  std::cout << " done ! " << std::endl;
231  }
232 
233 
234  // ---------------------------------------------------------------
235  // We define then the ETFESpace, that we suppose scalar in this
236  // case. We also need a standard FESpace to perform the
237  // interpolation.
238  // ---------------------------------------------------------------
239 
240  if (verbose)
241  {
242  std::cout << " -- Building the ETFESpace ... " << std::flush;
243  }
244 
245  std::string uOrder ("P1");
246  std::shared_ptr<FESpace< mesh_Type, MapEpetra > > uSpace ( new FESpace< mesh_Type, MapEpetra > (meshPtr, uOrder, 1, Comm) );
247 
248  std::shared_ptr<ETFESpace< mesh_Type, MapEpetra, 3, 1 > > ETuSpace ( new ETFESpace< mesh_Type, MapEpetra, 3, 1 > (meshPtr, & (uSpace->refFE() ), & (uSpace->fe().geoMap() ), Comm) );
249 
250  if (verbose)
251  {
252  std::cout << " done ! " << std::endl;
253  }
254  if (verbose)
255  {
256  std::cout << " ---> Dofs: " << ETuSpace->dof().numTotalDof() << std::endl;
257  }
258 
259 
260  // ---------------------------------------------------------------
261  // We start with the computation of the right hand side. First of
262  // all, we reuse the procedure that we used in the tutorial 3,
263  // i.e., we interpolate the function fFct before integration.
264  // ---------------------------------------------------------------
265 
266  if (verbose)
267  {
268  std::cout << " -- Building the rhs via interpolation ... " << std::flush;
269  }
270 
271  vector_Type fInterpolated (ETuSpace->map(), Repeated);
272 
273  fInterpolated *= 0.0;
274 
275  uSpace->interpolate (fFct, fInterpolated, 0.0);
276 
277  vector_Type rhsET (ETuSpace->map(), Repeated);
278  rhsET *= 0.0;
279 
280  {
281  using namespace ExpressionAssembly;
282 
283  integrate ( elements (ETuSpace->mesh() ),
284  uSpace->qr() ,
285  ETuSpace,
286  value (ETuSpace, fInterpolated) *phi_i
287  )
288  >> rhsET;
289  }
290 
291  rhsET.globalAssemble();
292 
293  if (verbose)
294  {
295  std::cout << " done! " << std::endl;
296  }
297 
298  // ---------------------------------------------------------------
299  // We assemble now a similar right hand side but without using the
300  // interpolation step, i.e. with a L2 projection.
301  //
302  // To this aim, we use the exprssion "X" which represents the
303  // position (i.e. the position of the quadrature node).
304  //
305  // We also use the functor, with a shared pointer (to avoid copy
306  // of functors that would contain large data). The eval keyword
307  // is then used to evaluate the functor.
308  // ---------------------------------------------------------------
309 
310  if (verbose)
311  {
312  std::cout << " -- Building the rhs via functor ... " << std::flush;
313  }
314 
315  vector_Type rhsETfunctor (ETuSpace->map(), Repeated);
316  rhsETfunctor *= 0.0;
317 
318  {
319  using namespace ExpressionAssembly;
320 
321  std::shared_ptr<fFunctor> ffunctor (new fFunctor);
322 
323  integrate ( elements (ETuSpace->mesh() ),
324  uSpace->qr() ,
325  ETuSpace,
326  eval (ffunctor, X) *phi_i
327  )
328  >> rhsETfunctor;
329  }
330 
331  rhsETfunctor.globalAssemble();
332 
333  if (verbose)
334  {
335  std::cout << " done! " << std::endl;
336  }
337 
338 
339  // ---------------------------------------------------------------
340  // We take now a look at the SUPG stabilization. The term that we
341  // want to add is gamma (beta dot grad v)(beta dot grad u) where
342  // gamma is h/2|beta|.
343  //
344  // To get the diameter of the element considered (h), the keyword
345  // h_K is used.
346  //
347  // For the norm of the advection field (|beta|), we simply
348  // evaluate the norm functor with beta as argument. Remark that
349  // here, the norm of the advection field is known, so the functor
350  // is not strictly necessary. However, in other cases, it can be
351  // unknown, so the functor strategy must be used.
352  //
353  // Here is the resulting code:
354  // ---------------------------------------------------------------
355 
356 
357  if (verbose)
358  {
359  std::cout << " -- Assembly of the AD-SUPG ... " << std::flush;
360  }
361 
362  std::shared_ptr<matrix_Type> ETsystemMatrix (new matrix_Type ( ETuSpace->map() ) );
363  *ETsystemMatrix *= 0.0;
364 
365  {
366  using namespace ExpressionAssembly;
367 
368  VectorSmall<3> beta (0, 1.0, 2.0);
369 
370  std::shared_ptr<normFunctor> norm ( new normFunctor);
371 
372  norm->setExponent (2);
373 
374  integrate ( elements (ETuSpace->mesh() ),
375  uSpace->qr(),
376  ETuSpace,
377  ETuSpace,
378 
379  dot ( grad (phi_i) , grad (phi_j) )
380  + dot ( grad (phi_j) , beta ) *phi_i
381  + h_K * dot (grad (phi_i), beta) *dot (grad (phi_j), beta) / (2.0 * eval (norm, beta) )
382 
383  )
384  >> ETsystemMatrix;
385  }
386 
387  if (verbose)
388  {
389  std::cout << " done! " << std::endl;
390  }
391 
392 
393  // ---------------------------------------------------------------
394  // Finally, we compute the difference between the two right hand
395  // sides computed previously. The difference should not be too
396  // large but is not supposed to be zero (because the interpolation
397  // and the L2 projection are not the same operations).
398  // ---------------------------------------------------------------
399 
400  if (verbose)
401  {
402  std::cout << " -- Computing the error ... " << std::flush;
403  }
404 
405  vector_Type checkRhs (ETuSpace->map(), Repeated);
406  checkRhs *= 0.0;
407 
408  checkRhs += rhsET;
409  checkRhs -= rhsETfunctor;
410 
411  checkRhs.globalAssemble();
412 
413  vector_Type checkRhsUnique (checkRhs, Unique);
414 
415  Real diffRhsNorm ( checkRhsUnique.normInf() );
416 
417  if (verbose)
418  {
419  std::cout << " done! " << std::endl;
420  }
421  if (verbose)
422  {
423  std::cout << " Rhs diff : " << diffRhsNorm << std::endl;
424  }
425 
426 
427  // ---------------------------------------------------------------
428  // We finalize the MPI if needed.
429  // ---------------------------------------------------------------
430 
431 #ifdef HAVE_MPI
432  MPI_Finalize();
433 #endif
434 
435 
436  // ---------------------------------------------------------------
437  // We finally compare the difference with the tolerance of the
438  // test.
439  // ---------------------------------------------------------------
440 
441  Real testTolerance (1e-3);
442 
443  if (diffRhsNorm < testTolerance)
444  {
445  return ( EXIT_SUCCESS );
446  }
447  return ( EXIT_FAILURE );
448 }
int main(int argc, char **argv)
MatrixEpetra< Real > matrix_Type
Real const & operator[](UInt const &i) const
Operator [].
function_Type fFct(fFctRaw)
Real fFctRaw(const Real &, const Real &x, const Real &, const Real &, const ID &)
uint32_type ID
IDs.
Definition: LifeV.hpp:194
return_Type operator()(const VectorSmall< 3 > &position)
double Real
Generic real data.
Definition: LifeV.hpp:175
return_Type operator()(const VectorSmall< 3 > &advection_field)
RegionMesh< LinearTetra > mesh_Type
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191
FESpace< mesh_Type, MapEpetra >::function_Type function_Type