LifeV
lifev/eta/tutorials/5_ETA_debug_expressions/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 explaining how to debug a failing expression.
30 
31  @author Samuel Quinodoz <samuel.quinodoz@epfl.ch>
32  @date 29-06-2012
33 
34  The ETA framework relies heavily on template mechanisms to
35  work. This provides a clean interface and good performances.
36  A drawback is that the compilation errors that one can get
37  when making a mistake in the expression are extremly
38  complicated and nearly impossible to understand for non-expert
39  developers.
40 
41  We explain here how to find out where is the problem and what
42  are the exact criteria that makes an expression well-formed
43  or ill-formed.
44 
45  Tutorials that should be read before: 1,2
46 
47  */
48 
49 // ---------------------------------------------------------------
50 // We include the usual headers (see tutorial 1 for explanations)
51 // ---------------------------------------------------------------
52 
53 
54 #include <Epetra_ConfigDefs.h>
55 #ifdef EPETRA_MPI
56 #include <mpi.h>
57 #include <Epetra_MpiComm.h>
58 #else
59 #include <Epetra_SerialComm.h>
60 #endif
61 
62 
63 #include <lifev/core/LifeV.hpp>
64 
65 #include <lifev/core/mesh/MeshPartitioner.hpp>
66 #include <lifev/core/mesh/RegionMesh3DStructured.hpp>
67 #include <lifev/core/mesh/RegionMesh.hpp>
68 #include <lifev/core/array/MatrixEpetra.hpp>
69 #include <lifev/eta/fem/ETFESpace.hpp>
70 #include <lifev/eta/expression/Integrate.hpp>
71 
72 #include <boost/shared_ptr.hpp>
73 
74 
75 // ---------------------------------------------------------------
76 // As usual, we work in the LifeV namespace. For clarity, we also
77 // make two typedefs for the mesh type and matrix type. We define
78 // then the MPI communicator.
79 // ---------------------------------------------------------------
80 
81 using namespace LifeV;
82 
84 typedef MatrixEpetra<Real> matrix_Type;
85 
86 
87 int main ( int argc, char** argv )
88 {
89 
90 #ifdef HAVE_MPI
91  MPI_Init (&argc, &argv);
92  std::shared_ptr<Epetra_Comm> Comm (new Epetra_MpiComm (MPI_COMM_WORLD) );
93 #else
94  std::shared_ptr<Epetra_Comm> Comm (new Epetra_SerialComm);
95 #endif
96 
97  const bool verbose (Comm->MyPID() == 0);
98 
99 
100  // ---------------------------------------------------------------
101  // The next step is to build the mesh. We use here a structured
102  // cartesian mesh over the square domain (-1,1)x(-1,1)x(-1,1).
103  // The mesh is the partitioned for the parallel computations and
104  // the original mesh is deleted.
105  // ---------------------------------------------------------------
106 
107  if (verbose)
108  {
109  std::cout << " -- Building and partitioning the mesh ... " << std::flush;
110  }
111 
112  const UInt Nelements (10);
113 
114  std::shared_ptr< mesh_Type > fullMeshPtr (new mesh_Type ( Comm ) );
115 
116  regularMesh3D ( *fullMeshPtr, 1, Nelements, Nelements, Nelements, false,
117  2.0, 2.0, 2.0,
118  -1.0, -1.0, -1.0);
119 
120  std::shared_ptr< mesh_Type > meshPtr;
121  {
122  MeshPartitioner< mesh_Type > meshPart (fullMeshPtr, Comm);
123  meshPtr = meshPart.meshPartition();
124  }
125 
126  fullMeshPtr.reset();
127 
128  if (verbose)
129  {
130  std::cout << " done ! " << std::endl;
131  }
132 
133 
134  // ---------------------------------------------------------------
135  // We start the discussion with the scalar case, so we define a
136  // scalar finite element space and the corresponding matrix.
137  // ---------------------------------------------------------------
138 
139  if (verbose)
140  {
141  std::cout << " -- Building the scalar ETFESpace ... " << std::flush;
142  }
143 
144  std::shared_ptr<ETFESpace< mesh_Type, MapEpetra, 3, 1 > > scalarSpace
145  ( new ETFESpace< mesh_Type, MapEpetra, 3, 1 > (meshPtr, &feTetraP1, Comm) );
146 
147  if (verbose)
148  {
149  std::cout << " done ! " << std::endl;
150  }
151  if (verbose)
152  {
153  std::cout << " ---> Dofs: " << scalarSpace->dof().numTotalDof() << std::endl;
154  }
155 
156  if (verbose)
157  {
158  std::cout << " -- Defining the matrix ... " << std::flush;
159  }
160 
161  if (verbose)
162  {
163  std::cout << " -- Defining the matrix ... " << std::flush;
164  }
165 
166  std::shared_ptr<matrix_Type> scalarMatrix (new matrix_Type ( scalarSpace->map() ) );
167 
168  *scalarMatrix *= 0.0;
169 
170  if (verbose)
171  {
172  std::cout << " done! " << std::endl;
173  }
174 
175  if (verbose)
176  {
177  std::cout << " done! " << std::endl;
178  }
179 
180  // ---------------------------------------------------------------
181  // We can now start the assembly. To understand whether an
182  // expression is valid, the critical observation is that every
183  // piece of expression is associated to a "fictitious" type (in
184  // the sense that it is not the type of the expression in the
185  // C++ sense), which matches the mathematical type.
186  //
187  // For example, in the case of a scalar finite element space, the
188  // basis functions are scalar quantities, while their gradients
189  // are vectorial quantities.
190  //
191  // With this in mind, we can now formulate the rules for an
192  // expression to be valid:
193  //
194  // Rule A: The combinaisons between two expressions (through an
195  // operator or a function) must be valid. For example, it is not
196  // possible to sum a vectorial quantity and a scalar quantity.
197  //
198  // Rule B: The overall expression must be a scalar quantity. For
199  // example, it not possible to integrate simply grad(phi_i)).
200  //
201  //
202  // ---------------------------------------------------------------
203 
204  // ---------------------------------------------------------------
205  // We can now start the assembly. To understand whether an
206  // expression is valid, the critical observation is that every
207  // piece of expression is associated to a "fictitious" type (in
208  // the sense that it is not the type of the expression in the
209  // C++ sense), which matches the mathematical type.
210  //
211  // For example, in the case of a scalar finite element space, the
212  // basis functions are scalar quantities, while their gradients
213  // are vectorial quantities.
214  //
215  // With this in mind, we can now formulate the rules for an
216  // expression to be valid:
217  //
218  // Rule A: The combinaisons between two expressions (through an
219  // operator or a function) must be valid. For example, it is not
220  // possible to sum a vectorial quantity and a scalar quantity.
221  //
222  // Rule B: The overall expression must be a scalar quantity. For
223  // example, it not possible to integrate simply grad(phi_i)).
224  //
225  //
226  // ---------------------------------------------------------------
227 
228  if (verbose)
229  {
230  std::cout << " -- Assembling the scalar matrix ... " << std::flush;
231  }
232 
233  {
234  using namespace ExpressionAssembly;
235 
236  // This would NOT compile (Rule A)
237  // Indeed,
238  // grad(phi_i) is a vectorial quantity
239  // grad(phi_j) is a vectorial quantity
240  // but the product between two vectors is not
241  // defined. If you mean the scalar product, you
242  // should use the dot function.
243 
244  /*integrate( elements(scalarSpace->mesh()),
245  quadRuleTetra4pt,
246  scalarSpace,
247  scalarSpace,
248 
249  grad(phi_i) * grad(phi_j)
250  )
251  >> scalarMatrix;
252  */
253 
254  // This would NOT compile (Rule B)
255  // Indeed,
256  // grad(phi_i) is a vectorial quantity
257  // phi_j is a scalar quantity
258  // the product between a scalar quantity and
259  // a vectorial quantity is well defined and
260  // yield a vectorial quantity.
261  // However, the whole expression is a vectorial
262  // quantity, therefore, it is not possible to
263  // integrate it.
264 
265  /*integrate( elements(scalarSpace->mesh()),
266  quadRuleTetra4pt,
267  scalarSpace,
268  scalarSpace,
269 
270  grad(phi_i) * phi_j
271  )
272  >> scalarMatrix;
273  */
274 
275 
276  // This compile because Rule A and Rule B
277  // are respected, and even if the expression
278  // does not correspond to any real problem.
279 
280  VectorSmall<3> V1 (1.0, 0.0, 0.0);
281 
282  integrate ( elements (scalarSpace->mesh() ),
283  quadRuleTetra4pt,
284  scalarSpace,
285  scalarSpace,
286  dot ( grad (phi_i) , grad (phi_j) )
287  + 0.0 *
288  (2.0 * phi_i / phi_j
289  - dot ( grad (phi_i), phi_i * V1) *phi_j
290  + 3.1415)
291  )
292  >> scalarMatrix;
293  }
294 
295  if (verbose)
296  {
297  std::cout << " done! " << std::endl;
298  }
299 
300 
301  // ---------------------------------------------------------------
302  // The rule A and B are very simple, usually much more than the
303  // compilation errors that can be issued. In case of problem, it
304  // is then much easier to look at the expression with the rules A
305  // and B to find where is the problem.
306  //
307  // To finish this tutorial, we compare the norm of the matrix with
308  // the norm it should have.
309  // ---------------------------------------------------------------
310 
311  if (verbose)
312  {
313  std::cout << " -- Closing the matrix ... " << std::flush;
314  }
315 
316  scalarMatrix->globalAssemble();
317 
318  if (verbose)
319  {
320  std::cout << " done ! " << std::endl;
321  }
322 
323  Real matrixNorm ( scalarMatrix->normInf() );
324 
325  if (verbose)
326  {
327  std::cout << " Matrix norm : " << matrixNorm << std::endl;
328  }
329 
330 #ifdef HAVE_MPI
331  MPI_Finalize();
332 #endif
333 
334  Real matrixNormDiff (std::abs (matrixNorm - 3.2) );
335 
336  if (verbose)
337  {
338  std::cout << " Error : " << matrixNormDiff << std::endl;
339  }
340 
341  Real testTolerance (1e-10);
342 
343  if ( matrixNormDiff < testTolerance )
344  {
345  return ( EXIT_SUCCESS );
346  }
347  return ( EXIT_FAILURE );
348 
349 }
int main(int argc, char **argv)
MatrixEpetra< Real > matrix_Type
double Real
Generic real data.
Definition: LifeV.hpp:175
RegionMesh< LinearTetra > mesh_Type