LifeV
lifev/eta/tutorials/3_ETA_rhs_and_value/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 assembly of a right hand side and the computation of
30  benchmark values.
31 
32  @author Samuel Quinodoz <samuel.quinodoz@epfl.ch>
33  @date 29-06-2012
34 
35  In this tutorial, we show how to assemble a right hand side and compute a
36  volume integral, using the ETA framework.
37 
38  Tutorials that should be read before: 1,2
39 
40  */
41 
42 // ---------------------------------------------------------------
43 // We use the same files as for the tutorial 2, nothing else is
44 // required to compute a right hand side or a value.
45 // ---------------------------------------------------------------
46 
47 
48 #include <Epetra_ConfigDefs.h>
49 #ifdef EPETRA_MPI
50 #include <mpi.h>
51 #include <Epetra_MpiComm.h>
52 #else
53 #include <Epetra_SerialComm.h>
54 #endif
55 
56 
57 
58 #include <lifev/core/LifeV.hpp>
59 
60 #include <lifev/core/mesh/MeshPartitioner.hpp>
61 #include <lifev/core/mesh/RegionMesh3DStructured.hpp>
62 #include <lifev/core/mesh/RegionMesh.hpp>
63 
64 #include <lifev/core/array/MatrixEpetra.hpp>
65 #include <lifev/core/array/VectorEpetra.hpp>
66 
67 #include <lifev/eta/fem/ETFESpace.hpp>
68 #include <lifev/eta/expression/Integrate.hpp>
69 
70 #include <boost/shared_ptr.hpp>
71 
72 #include <lifev/core/fem/FESpace.hpp>
73 #include <lifev/core/solver/ADRAssembler.hpp>
74 
75 
76 // ---------------------------------------------------------------
77 // All the work is done in the namespace LifeV. We also define
78 // the mesh type and the vector type. The matrix type is also
79 // required for the classical way of assembling.
80 // ---------------------------------------------------------------
81 
82 using namespace LifeV;
83 
85 typedef VectorEpetra vector_Type;
86 typedef MatrixEpetra<Real> matrix_Type;
87 typedef FESpace<mesh_Type, MapEpetra>::function_Type function_Type;
88 
89 
90 // ---------------------------------------------------------------
91 // The assembly of the right hand side by the ADRAssembler
92 // requires the definition of a free function. We take it here as
93 // a constant in space.
94 //
95 // We will also integrate a function over the whole domain. We
96 // chose the function g(x,y,z)=x so that an exact value for the
97 // integral is known.
98 // ---------------------------------------------------------------
99 
100 Real fRhsRaw ( const Real& /* t */, const Real& /*x*/, const Real& /*y*/, const Real& /* z */ , const ID& /* i */ )
101 {
102  return 2;
103 }
104 function_Type fRhs (fRhsRaw);
105 
106 Real gRaw ( const Real& /* t */, const Real& x, const Real& /*y*/, const Real& /* z */ , const ID& /* i */ )
107 {
108  return x;
109 }
110 function_Type g (gRaw);
111 
112 
113 // ---------------------------------------------------------------
114 // As in the previous tutorials, we start the execution by
115 // constructing the MPI communicator.
116 // ---------------------------------------------------------------
117 
118 int main ( int argc, char** argv )
119 {
120 
121 #ifdef HAVE_MPI
122  MPI_Init (&argc, &argv);
123  std::shared_ptr<Epetra_Comm> Comm (new Epetra_MpiComm (MPI_COMM_WORLD) );
124 #else
125  std::shared_ptr<Epetra_Comm> Comm (new Epetra_SerialComm);
126 #endif
127 
128  const bool verbose (Comm->MyPID() == 0);
129 
130 
131  // ---------------------------------------------------------------
132  // We define the mesh: the domain is (-1,1)x(-1,1)x(-1,1) and the
133  // mesh structured. We also partition the mesh.
134  // ---------------------------------------------------------------
135 
136  if (verbose)
137  {
138  std::cout << " -- Building and partitioning the mesh ... " << std::flush;
139  }
140 
141  const UInt Nelements (10);
142 
143  std::shared_ptr< mesh_Type > fullMeshPtr (new mesh_Type ( Comm ) );
144 
145  regularMesh3D ( *fullMeshPtr, 1, Nelements, Nelements, Nelements, false,
146  2.0, 2.0, 2.0,
147  -1.0, -1.0, -1.0);
148 
149  std::shared_ptr< mesh_Type > meshPtr;
150  {
151  MeshPartitioner< mesh_Type > meshPart (fullMeshPtr, Comm);
152  meshPtr = meshPart.meshPartition();
153  }
154 
155  fullMeshPtr.reset();
156 
157  if (verbose)
158  {
159  std::cout << " done ! " << std::endl;
160  }
161 
162 
163  // ---------------------------------------------------------------
164  // As in tutorial 2, we define now both FESpace and ETFESpace, for
165  // the sake of comparison.
166  // ---------------------------------------------------------------
167 
168  if (verbose)
169  {
170  std::cout << " -- Building the FESpace ... " << std::flush;
171  }
172 
173  std::string uOrder ("P1");
174  std::shared_ptr<FESpace< mesh_Type, MapEpetra > > uSpace ( new FESpace< mesh_Type, MapEpetra > (meshPtr, uOrder, 1, Comm) );
175 
176  if (verbose)
177  {
178  std::cout << " done ! " << std::endl;
179  }
180  if (verbose)
181  {
182  std::cout << " ---> Dofs: " << uSpace->dof().numTotalDof() << std::endl;
183  }
184 
185  if (verbose)
186  {
187  std::cout << " -- Building the ETFESpace ... " << std::flush;
188  }
189 
190  std::shared_ptr<ETFESpace< mesh_Type, MapEpetra, 3, 1 > > ETuSpace ( new ETFESpace< mesh_Type, MapEpetra, 3, 1 > (meshPtr, & (uSpace->refFE() ), & (uSpace->fe().geoMap() ), Comm) );
191 
192  if (verbose)
193  {
194  std::cout << " done ! " << std::endl;
195  }
196  if (verbose)
197  {
198  std::cout << " ---> Dofs: " << ETuSpace->dof().numTotalDof() << std::endl;
199  }
200 
201 
202  // ---------------------------------------------------------------
203  // We proceed now with the assembly of the right hand sides. For
204  // the classical way, we need to interpolate the function and then
205  // call the corresponding method in the ADRAssembler class.
206  // ---------------------------------------------------------------
207 
208  if (verbose)
209  {
210  std::cout << " -- Classical way ... " << std::flush;
211  }
212 
213  vector_Type fInterpolated (uSpace->map(), Repeated);
214 
215  fInterpolated = 0.0;
216 
217  uSpace->interpolate (fRhs, fInterpolated, 0.0);
218 
219  vector_Type rhs (uSpace->map(), Repeated);
220 
221  rhs = 0.0;
222 
223  ADRAssembler<mesh_Type, matrix_Type, vector_Type> adrAssembler;
224 
225  adrAssembler.setup (uSpace, uSpace);
226 
227  adrAssembler.addMassRhs (rhs, fInterpolated);
228 
229  rhs.globalAssemble();
230 
231  if (verbose)
232  {
233  std::cout << " done ! " << std::endl;
234  }
235 
236 
237  // ---------------------------------------------------------------
238  // Now we perform the same assembly with the ETA framework.
239  //
240  // The assembly looks very similar to those seen in the previous
241  // tutorials. The main differences are:
242  //
243  // - There is one less argument in the integrate function.
244  // Indeed, the trial space (solution space) does not make sense
245  // when assembling the right hand side.
246  //
247  // - The expression to integrate is different. Remark that using
248  // the keyword phi_j in the expression to integrate would result
249  // in a compilation error. Indeed, phi_j refers to the trial
250  // space, which is not defined here.
251  //
252  // ---------------------------------------------------------------
253 
254  if (verbose)
255  {
256  std::cout << " -- ETA way ... " << std::flush;
257  }
258 
259  vector_Type rhsET (ETuSpace->map(), Repeated);
260  rhsET = 0.0;
261 
262  {
263  using namespace ExpressionAssembly;
264 
265  integrate ( elements (ETuSpace->mesh() ),
266  uSpace->qr() ,
267  ETuSpace,
268  value (ETuSpace, fInterpolated) *phi_i
269  )
270  >> rhsET;
271  }
272 
273  rhsET.globalAssemble();
274 
275  if (verbose)
276  {
277  std::cout << " done ! " << std::endl;
278  }
279 
280 
281  // ---------------------------------------------------------------
282  // We remark that in this particular case, since the function
283  // is constant, we could directly use the value of the constant
284  // in the expression, thus avoiding the interpolation step.
285  //
286  // The following code would then yield the same results.
287  // ---------------------------------------------------------------
288  /*
289  if (verbose) std::cout << " -- ETA way ... " << std::flush;
290 
291  vector_Type rhsET(ETuSpace->map(),Repeated);
292  rhsET=0.0;
293 
294  {
295  using namespace ExpressionAssembly;
296 
297  integrate( elements(ETuSpace->mesh()),
298  uSpace->qr() ,
299  ETuSpace,
300  2.0*phi_i
301  )
302  >> rhsET;
303  }
304 
305  rhsET.globalAssemble();
306 
307  if (verbose) std::cout << " done ! " << std::endl;
308  */
309 
310  // ---------------------------------------------------------------
311  // Before checking that the two right hand sides that we assembled
312  // are legal, we also integrate values on the domain.
313  //
314  // Integrating values is again slightly different than the other
315  // integrations.
316  //
317  // We start by integrating the function g on the
318  // domain. In this tutorial, we interpolate the function g to
319  // integrate it. Another way would be to pass through functors
320  // (which is explained in another tutorial).
321  //
322  // The result of the integration is put in a simple scalar value.
323  //
324  // The integrate function is now another argument less: no space
325  // for the test function (nor for the trial functions) is given
326  // in argument. The keyword phi_i (and the keyword phi_j) are
327  // illegal in the expression and using it would result in a
328  // compilation error.
329  // ---------------------------------------------------------------
330 
331  if (verbose)
332  {
333  std::cout << " -- Integrating g ... " << std::flush;
334  }
335 
336  vector_Type gInterpolated (uSpace->map(), Repeated);
337 
338  gInterpolated = 0.0;
339 
340  uSpace->interpolate (g, gInterpolated, 0.0);
341 
342  Real localIntegralg (0.0);
343 
344  {
345  using namespace ExpressionAssembly;
346 
347  integrate ( elements (ETuSpace->mesh() ),
348  uSpace->qr() ,
349  value (ETuSpace, gInterpolated)
350  )
351  >> localIntegralg;
352  }
353 
354 
355  // ---------------------------------------------------------------
356  // When assembling a matrix or a vector, the computed local
357  // contributions are communicated, if necessary, to the other
358  // processes when the globalAssemble method is called. There is
359  // no such method for scalar constants.
360 
361  // The communication must therefore be performed "by hand",
362  // through the MPI SumAll instruction, which sums the
363  // contributions of all the processes.
364  //
365  // Before performing the sum, when use a Barrier, which ensures
366  // that all the processes have computed their contributions.
367  // ---------------------------------------------------------------
368 
369  Real globalIntegralg (0.0);
370 
371  Comm->Barrier();
372  Comm->SumAll (&localIntegralg, &globalIntegralg, 1);
373 
374  if (verbose)
375  {
376  std::cout << " done ! " << std::endl;
377  }
378 
379 
380  // ---------------------------------------------------------------
381  // We present finally a small example which corresponds to an
382  // exception with respect to what has been said before: we stated
383  // that the scalar constants can be used without adaptation in the
384  // expressions. This is true as long as the expression does not
385  // reduce to a scalar constant.
386  //
387  // For example, if we want to compute the volume of the domain,
388  // which is the integral of 1 over it, we need to use the function
389  // value (otherwise a compilation error is issued). Remark that
390  // the value function can also be used for the constants in
391  // all the expressions, but it is then only facultative.
392  //
393  // Again, to get the global volume, we need to sum the different
394  // contributions.
395  // ---------------------------------------------------------------
396 
397  if (verbose)
398  {
399  std::cout << " -- Computing the volume ... " << std::flush;
400  }
401 
402  Real localVolume (0.0);
403 
404  {
405  using namespace ExpressionAssembly;
406 
407  // This would create a compilation error
408  /*
409  integrate( elements(ETuSpace->mesh()),
410  uSpace->qr() ,
411  1.0
412  )
413  >> localVolume;
414  */
415 
416  // This is the right synthax
417  integrate ( elements (ETuSpace->mesh() ),
418  uSpace->qr() ,
419  value (1.0)
420  )
421  >> localVolume;
422  }
423 
424  Real globalVolume (0.0);
425 
426  Comm->Barrier();
427  Comm->SumAll (&localVolume, &globalVolume, 1);
428 
429  if (verbose)
430  {
431  std::cout << " done ! " << std::endl;
432  }
433 
434 
435  // ---------------------------------------------------------------
436  // Finally, we check that the two right hand sides are similar
437  // with the two assembly procedures. We also check that the two
438  // integrals correspond to their exact values.
439  // ---------------------------------------------------------------
440 
441  vector_Type checkRhs (ETuSpace->map(), Repeated);
442  checkRhs = 0.0;
443 
444  checkRhs += rhs;
445  checkRhs -= rhsET;
446 
447  checkRhs.globalAssemble();
448 
449  vector_Type checkRhsUnique (checkRhs, Unique);
450 
451  Real errorRhsNorm ( checkRhsUnique.normInf() );
452 
453  Real errorIntegralg (std::abs ( globalIntegralg - 0.0) );
454 
455  Real errorVolume (std::abs ( globalVolume - 8.0) );
456 
457  if (verbose)
458  {
459  std::cout << " Rhs error : " << errorRhsNorm << std::endl;
460  }
461  if (verbose)
462  {
463  std::cout << " Integral error : " << errorIntegralg << std::endl;
464  }
465  if (verbose)
466  {
467  std::cout << " Volume error : " << errorVolume << std::endl;
468  }
469 
470 
471  // ---------------------------------------------------------------
472  // As usual, finalize the MPI if needed.
473  // ---------------------------------------------------------------
474 
475 #ifdef HAVE_MPI
476  MPI_Finalize();
477 #endif
478 
479 
480  // ---------------------------------------------------------------
481  // Finally, we test the error with respect to the test tolerance.
482  // ---------------------------------------------------------------
483 
484  Real testTolerance (1e-10);
485 
486  if ( (errorRhsNorm < testTolerance)
487  && (errorIntegralg < testTolerance)
488  && (errorVolume < testTolerance) )
489  {
490  return ( EXIT_SUCCESS );
491  }
492  return ( EXIT_FAILURE );
493 }
int main(int argc, char **argv)
MatrixEpetra< Real > matrix_Type
Real gRaw(const Real &, const Real &x, const Real &, const Real &, const ID &)
Real fRhsRaw(const Real &, const Real &, const Real &, const Real &, const ID &)
uint32_type ID
IDs.
Definition: LifeV.hpp:194
double Real
Generic real data.
Definition: LifeV.hpp:175
function_Type fRhs(fRhsRaw)
RegionMesh< LinearTetra > mesh_Type
function_Type g(gRaw)
FESpace< mesh_Type, MapEpetra >::function_Type function_Type