LifeV
lifev/eta/tutorials/10_ETA_QR_Advanced/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 Advanced tutorial about the quadrature in the ETA.
30 
31  @author Samuel Quinodoz <samuel.quinodoz@epfl.ch>
32  @date 08-08-2012
33 
34  This tutorial shows an advanced feature of the ETA framework:
35  adaptative quadratures.
36 
37  Indeed, the ETA framework allows the user to define different
38  ways to integrate, that have possibly not been forseen before,
39  without having to enter the whole machinery.
40 
41  In this tutorial, we show how to create an "adaptative"
42  quadrature rule which consists in a standard quadrature
43  rule excepted for some precise elements where the integral
44  is known to be discontinuous. In the elements crossed by this
45  discontinuity, we implement a Monte-Carlo type integral
46  (which is probably not the best way to compute the integral,
47  but for this example, this is fine).
48 
49  Please, read tutorial 1, 3, 6 and 9 before reading this tutorial.
50  */
51 
52 // ---------------------------------------------------------------
53 // We include here exactly the same files that in tutorial 1,
54 // excepted for the QRAdapterBase.hpp file and the cstdlib, which
55 // is needed for the generation of the random numbers.
56 // ---------------------------------------------------------------
57 
58 #pragma GCC diagnostic ignored "-Wunused-variable"
59 #pragma GCC diagnostic ignored "-Wunused-parameter"
60 
61 #include <Epetra_ConfigDefs.h>
62 #ifdef EPETRA_MPI
63 #include <mpi.h>
64 #include <Epetra_MpiComm.h>
65 #else
66 #include <Epetra_SerialComm.h>
67 #endif
68 
69 #pragma GCC diagnostic warning "-Wunused-variable"
70 #pragma GCC diagnostic warning "-Wunused-parameter"
71 
72 
73 #include <lifev/core/LifeV.hpp>
74 
75 #include <lifev/core/mesh/MeshPartitioner.hpp>
76 #include <lifev/core/mesh/RegionMesh3DStructured.hpp>
77 #include <lifev/core/mesh/RegionMesh.hpp>
78 
79 #include <lifev/core/array/MatrixEpetra.hpp>
80 
81 #include <lifev/eta/fem/ETFESpace.hpp>
82 
83 #include <lifev/eta/expression/Integrate.hpp>
84 
85 #include <lifev/eta/fem/QRAdapterBase.hpp>
86 
87 #include <boost/shared_ptr.hpp>
88 
89 #include <cstdlib>
90 
91 using namespace LifeV;
92 
93 // ---------------------------------------------------------------
94 // We start directly with the definition of the class that we
95 // will need for the adaptative quadrature.
96 //
97 // Remark that, for the sake of this tutorial, we implement all
98 // the methods "inline", while it should be located in a separated
99 // .hpp file.
100 //
101 // First of all, the class is template on the mesh type,
102 // which is quite standard for the LifeV class, to avoid
103 // depending on a specific type of mesh (even if we suppose that
104 // it contains only tetrahedra).
105 //
106 // Then, we make the class derive from the QRAdapterBase class,
107 // which takes in argument exactly the name of the class. This is
108 // required by the ETA framework to recognize that this object is
109 // used to define a quadrature.
110 // ---------------------------------------------------------------
111 
112 template< typename MeshType >
113 class MCQuadrature : public QRAdapterBase< MCQuadrature <MeshType> >
114 {
115 
116 private:
117 
118  // ---------------------------------------------------------------
119  // A small typedef for convenience.
120  // ---------------------------------------------------------------
121 
122  typedef QRAdapterBase< MCQuadrature<MeshType> > base_Type;
123 
124  // ---------------------------------------------------------------
125  // We start the description of the class by the members that it
126  // will contains.
127  //
128  // This class contains:
129  // - a quadrature rule : the unadapted quadrature
130  // - a pointer to a quadrature rule : the adapted quadrature
131  // - a pointer to the mesh
132  // - a boolean indicating whether to use the adapted quadrature
133  // or not.
134  // - an integer representing the number of Monte-Carlo points
135  // that we want for the quadrature.
136  // ---------------------------------------------------------------
137 
139 
141 
143 
145 
147 
148 public:
149 
150  // ---------------------------------------------------------------
151  // There is a fixed interface that must be present for the class
152  // to work properly. They are:
153  // - a copy constructor
154  // - the update method
155  // - the isAdaptedElement getter
156  // - the standardQR getter
157  // - the adaptedQR getter
158  //
159  // These elements are mandatory, other interfaces can of course
160  // be added! We here add another constructor.
161  // ---------------------------------------------------------------
162 
163  // ---------------------------------------------------------------
164  // Simple copy constructor
165  // ---------------------------------------------------------------
166 
167  MCQuadrature ( const MCQuadrature<MeshType>& qr)
168  : base_Type(),
169  M_stdQR (qr.M_stdQR),
171  M_mesh (qr.M_mesh),
172  M_isAdaptedElement (qr.M_isAdaptedElement),
173  M_nbPoints (qr.M_nbPoints)
174  {}
175 
176  // ---------------------------------------------------------------
177  // This method should compute whether the element needs an
178  // adapted quadrature or not, and if yes, it compute the
179  // quadrature.
180  //
181  // We delegate here the work to a private method.
182  // ---------------------------------------------------------------
183 
184  void update (UInt elementID)
185  {
186  computeQuadRule (elementID);
187  }
188 
189 
190  // ---------------------------------------------------------------
191  // Says if the element (for which the update has been called)
192  // needs an adapted quadrature.
193  // ---------------------------------------------------------------
194 
195  bool isAdaptedElement() const
196  {
197  return M_isAdaptedElement;
198  }
199 
200 
201  // ---------------------------------------------------------------
202  // Getter for the non adapted QR.
203  // ---------------------------------------------------------------
204 
205  const QuadratureRule& standardQR() const
206  {
207  return M_stdQR;
208  }
209 
210 
211  // ---------------------------------------------------------------
212  // Getter for the adapted QR.
213  // ---------------------------------------------------------------
214 
215  const QuadratureRule& adaptedQR() const
216  {
217  return *M_adaptedQR;
218  }
219 
220 
221  // ---------------------------------------------------------------
222  // Our special constructor, which uses the mesh, the non-adapted
223  // quadrature rule and the number of Monte-Carlo points.
224  // ---------------------------------------------------------------
225 
226  MCQuadrature (std::shared_ptr<MeshType> mesh, const QuadratureRule& stdQR, const UInt& nbPoints)
227  : base_Type(),
228  M_stdQR (stdQR),
230  M_mesh (mesh),
231  M_isAdaptedElement (false),
232  M_nbPoints (nbPoints)
233  {}
234 
235 private:
236 
237  // ---------------------------------------------------------------
238  // Here is the core of the class: the computation of the
239  // quadrature rule if needed.
240  //
241  // The principle is to check whether the element is crossed by
242  // the discontinuity.
243  // - if yes, generate a Monte-Carlo quadrature
244  // - if no, use a standard quadrature rule.
245  // ---------------------------------------------------------------
246 
247  void computeQuadRule (UInt elementID)
248  {
249 
250  // ---------------------------------------------------------------
251  // We know that we want to adapt the quadrature if the element
252  // crosses the plan given by x-2y=0. To know
253  // we an element is crossed, we check the sign of x-2y (which
254  // is positive on one side and negative on the other). If we
255  // get both signes, we need to adapt the quadrature.
256  // ---------------------------------------------------------------
257 
258  bool positiveVertices (false);
259  bool negativeVertices (false);
260 
261  for (UInt iterVertex (0); iterVertex < 4; ++iterVertex)
262  {
263  Real x (M_mesh->element (elementID).point (iterVertex).coordinate (0) );
264  Real y (M_mesh->element (elementID).point (iterVertex).coordinate (1) );
265 
266  if (x - 2 * y < 0)
267  {
268  negativeVertices = true;
269  }
270  else if (x - 2 * y > 0)
271  {
272  positiveVertices = true;
273  };
274  // If a vertex gives zero, we do not care about it!
275  }
276 
277  M_isAdaptedElement = ( positiveVertices && negativeVertices );
278 
279  // ---------------------------------------------------------------
280  // Now, if the element is to be adapted, we generate the Monte-
281  // Carlo quadrature.
282  // ---------------------------------------------------------------
283 
284  if (M_isAdaptedElement)
285  {
286  M_adaptedQR.reset (new QuadratureRule ("Monte-Carlo", TETRA, 3, 0, 0) );
287 
288  UInt nbPts (0);
289  while ( nbPts < M_nbPoints)
290  {
291  Real x ( std::rand() / Real (RAND_MAX) );
292  Real y ( std::rand() / Real (RAND_MAX) );
293  Real z ( std::rand() / Real (RAND_MAX) );
294 
295  if ( x + y + z <= 1)
296  {
297  M_adaptedQR->addPoint (QuadraturePoint (x, y, z, 1.0 / (6.0 * M_nbPoints) ) );
298  nbPts += 1;
299  }
300  } // end of while
301  } // end of if
302  }
303 };
304 
305 
306 // ---------------------------------------------------------------
307 // We define then the function to integrate: it is the indicator
308 // function of (x-2y>0).
309 // ---------------------------------------------------------------
310 
311 
312 class fFunctor
313 {
314 public:
315  typedef Real return_Type;
316 
317  return_Type operator() (const VectorSmall<3>& position)
318  {
319  if (position[0] - 2 * position[1] > 0)
320  {
321  return 1;
322  }
323  return 0;
324  }
325 
326  fFunctor() {}
327  fFunctor (const fFunctor&) {}
328  ~fFunctor() {}
329 };
330 
331 
332 // ---------------------------------------------------------------
333 // We proceed then exactly has described in tutorial 1 until the
334 // assembly procedure is reached.
335 // ---------------------------------------------------------------
336 
337 
339 typedef MatrixEpetra<Real> matrix_Type;
340 
341 
342 int main ( int argc, char** argv )
343 {
344 
345 #ifdef HAVE_MPI
346  MPI_Init (&argc, &argv);
347  std::shared_ptr<Epetra_Comm> Comm (new Epetra_MpiComm (MPI_COMM_WORLD) );
348 #else
349  std::shared_ptr<Epetra_Comm> Comm (new Epetra_SerialComm);
350 #endif
351 
352  const bool verbose (Comm->MyPID() == 0);
353 
354 
355  if (verbose)
356  {
357  std::cout << " -- Building and partitioning the mesh ... " << std::flush;
358  }
359 
360  const UInt Nelements (10);
361 
362  std::shared_ptr< mesh_Type > fullMeshPtr (new mesh_Type);
363 
364  regularMesh3D ( *fullMeshPtr, 1, Nelements, Nelements, Nelements, false,
365  2.0, 2.0, 2.0,
366  -1.0, -1.0, -1.0);
367 
368  MeshPartitioner< mesh_Type > meshPart (fullMeshPtr, Comm);
369 
370  fullMeshPtr.reset();
371 
372  if (verbose)
373  {
374  std::cout << " done ! " << std::endl;
375  }
376 
377 
378  // ---------------------------------------------------------------
379  // First of all, we compute the integral using a standard
380  // quadrature rule. We see that we do not get the correct answer
381  // (which is 4)
382  // ---------------------------------------------------------------
383 
384  if (verbose)
385  {
386  std::cout << " -- Computing the volume (std) ... " << std::flush;
387  }
388 
389  Real localIntegralStd (0.0);
390 
391  {
392  using namespace ExpressionAssembly;
393 
394  std::shared_ptr<fFunctor> fFct (new fFunctor);
395 
396  integrate ( elements (meshPart.meshPartition() ),
397  quadRuleTetra1pt,
398  eval (fFct, X)
399  )
400  >> localIntegralStd;
401  }
402 
403  Real globalIntegralStd (0.0);
404 
405  Comm->Barrier();
406  Comm->SumAll (&localIntegralStd, &globalIntegralStd, 1);
407 
408 
409  if (verbose)
410  {
411  std::cout << " done! " << std::endl;
412  }
413  if (verbose)
414  {
415  std::cout << " Integral: " << globalIntegralStd << std::endl;
416  }
417 
418 
419  // ---------------------------------------------------------------
420  // Now we use our adapted quadrature. We simply replace the
421  // quadrature by an instance of the quadrature adapter that we
422  // created.
423  // ---------------------------------------------------------------
424 
425  if (verbose)
426  {
427  std::cout << " -- Computing the volume (adapted) ... " << std::flush;
428  }
429 
430  Real localIntegralAdapted (0.0);
431 
432  {
433  using namespace ExpressionAssembly;
434 
435  std::shared_ptr<fFunctor> fFct (new fFunctor);
436 
437  MCQuadrature<mesh_Type> myQuad (meshPart.meshPartition(), quadRuleTetra1pt, 1e4);
438 
439  integrate ( elements (meshPart.meshPartition() ),
440  myQuad,
441  eval (fFct, X)
442  )
443  >> localIntegralAdapted;
444  }
445 
446  Real globalIntegralAdapted (0.0);
447 
448  Comm->Barrier();
449  Comm->SumAll (&localIntegralAdapted, &globalIntegralAdapted, 1);
450 
451 
452  if (verbose)
453  {
454  std::cout << " done! " << std::endl;
455  }
456  if (verbose)
457  {
458  std::cout << " Integral: " << globalIntegralAdapted << std::endl;
459  }
460 
461  // ---------------------------------------------------------------
462  // Finally, we check that the errors are not too high.
463  // ---------------------------------------------------------------
464 
465 
466 #ifdef HAVE_MPI
467  MPI_Finalize();
468 #endif
469 
470  if ( std::abs (4 - globalIntegralAdapted) < 1e-2 )
471  {
472  return ( EXIT_SUCCESS );
473  }
474  return ( EXIT_FAILURE );
475 
476 }
int main(int argc, char **argv)
QRAdapterBase< MCQuadrature< MeshType > > base_Type
MatrixEpetra< Real > matrix_Type
Real const & operator[](UInt const &i) const
Operator [].
MCQuadrature(const MCQuadrature< MeshType > &qr)
return_Type operator()(const VectorSmall< 3 > &position)
std::shared_ptr< QuadratureRule > M_adaptedQR
double Real
Generic real data.
Definition: LifeV.hpp:175
const QuadratureRule & standardQR() const
RegionMesh< LinearTetra > mesh_Type
MCQuadrature(std::shared_ptr< MeshType > mesh, const QuadratureRule &stdQR, const UInt &nbPoints)
QuadratureRule - The basis class for storing and accessing quadrature rules.
const QuadratureRule & adaptedQR() const
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191