LifeV
lifev/eta/tutorials/1_ETA_laplacian/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 introducing the expression assembly
30 
31  @author Samuel Quinodoz <samuel.quinodoz@epfl.ch>
32  @date 28-06-2012
33 
34  In this first tutorial, we assemble the matrix
35  associated to a scalar laplacian problem. The basics
36  of the ETA module are explained and are pushed further
37  in the next tutorials.
38 
39  ETA stands Expression Template Assembly, in reference
40  to the metaprogramming technique used.
41 
42  */
43 
44 // ---------------------------------------------------------------
45 // We include here the MPI headers for the parallel computations.
46 // ---------------------------------------------------------------
47 
48 
49 #include <Epetra_ConfigDefs.h>
50 #ifdef EPETRA_MPI
51 #include <mpi.h>
52 #include <Epetra_MpiComm.h>
53 #else
54 #include <Epetra_SerialComm.h>
55 #endif
56 
57 
58 
59 // ---------------------------------------------------------------
60 // We include then the required headers from LifeV. First of all,
61 // the definition file and mesh related files. We also include
62 // the MatrixEpetra since this is the kind of object that we want
63 // to assemble.
64 // ---------------------------------------------------------------
65 
66 #include <lifev/core/LifeV.hpp>
67 
68 #include <lifev/core/mesh/MeshPartitioner.hpp>
69 #include <lifev/core/mesh/RegionMesh3DStructured.hpp>
70 #include <lifev/core/mesh/RegionMesh.hpp>
71 
72 #include <lifev/core/array/MatrixEpetra.hpp>
73 
74 // ---------------------------------------------------------------
75 // In order to use the ETA framework, a special version of the
76 // FESpace structure must be used. It is called ETFESpace and
77 // has basically the same role as the FESpace.
78 // ---------------------------------------------------------------
79 
80 #include <lifev/eta/fem/ETFESpace.hpp>
81 
82 
83 // ---------------------------------------------------------------
84 // The most important file to include is the Integrate.hpp file
85 // which contains all the definitions required to perform the
86 // different integrations.
87 // ---------------------------------------------------------------
88 
89 #include <lifev/eta/expression/Integrate.hpp>
90 
91 
92 // ---------------------------------------------------------------
93 // Finally, we include shared pointer from boost since we use
94 // them explicitly in this tutorial.
95 // ---------------------------------------------------------------
96 
97 #include <boost/shared_ptr.hpp>
98 
99 
100 // ---------------------------------------------------------------
101 // As usual, we work in the LifeV namespace. For clarity, we also
102 // make two typedefs for the mesh type and matrix type.
103 // ---------------------------------------------------------------
104 
105 using namespace LifeV;
106 
108 typedef MatrixEpetra<Real> matrix_Type;
109 
110 
111 // ---------------------------------------------------------------
112 // We start the programm by the definition of the communicator
113 // (as usual) depending on whether MPI is available or not. We
114 // also define a boolean to allow only one process to display
115 // messages.
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  // The next step is to build the mesh. We use here a structured
133  // cartesian mesh over the square domain (-1,1)x(-1,1)x(-1,1).
134  // The mesh is the partitioned for the parallel computations and
135  // the original mesh is deleted.
136  // ---------------------------------------------------------------
137 
138  if (verbose)
139  {
140  std::cout << " -- Building and partitioning the mesh ... " << std::flush;
141  }
142 
143  const UInt Nelements (10);
144 
145  std::shared_ptr< mesh_Type > fullMeshPtr (new mesh_Type ( Comm ) );
146 
147  regularMesh3D ( *fullMeshPtr, 1, Nelements, Nelements, Nelements, false,
148  2.0, 2.0, 2.0,
149  -1.0, -1.0, -1.0);
150 
151  std::shared_ptr< mesh_Type > meshPtr;
152  {
153  MeshPartitioner< mesh_Type > meshPart (fullMeshPtr, Comm);
154  meshPtr = meshPart.meshPartition();
155  }
156 
157  fullMeshPtr.reset();
158 
159  if (verbose)
160  {
161  std::cout << " done ! " << std::endl;
162  }
163 
164 
165  // ---------------------------------------------------------------
166  // We define now the ETFESpace that we need for the assembly.
167  // Remark that we use a shared pointer because other structures
168  // will require this ETFESpace to be alive. We can also observe
169  // that the ETFESpace has more template parameters than the
170  // classical FESpace (this is the main difference). The 3
171  // indicates that the problem is in 3D while the 1 indicate that
172  // the unknown is scalar.
173  //
174  // After having constructed the ETFESpace, we display the number
175  // of degrees of freedom of the problem.
176  // ---------------------------------------------------------------
177 
178  if (verbose)
179  {
180  std::cout << " -- Building ETFESpaces ... " << std::flush;
181  }
182 
183  std::shared_ptr<ETFESpace< mesh_Type, MapEpetra, 3, 1 > > uSpace
184  ( new ETFESpace< mesh_Type, MapEpetra, 3, 1 > (meshPtr, &feTetraP1, Comm) );
185 
186  if (verbose)
187  {
188  std::cout << " done ! " << std::endl;
189  }
190  if (verbose)
191  {
192  std::cout << " ---> Dofs: " << uSpace->dof().numTotalDof() << std::endl;
193  }
194 
195 
196  // ---------------------------------------------------------------
197  // The matrix is then defined using the map of the FE space.
198  // ---------------------------------------------------------------
199 
200  if (verbose)
201  {
202  std::cout << " -- Defining the matrix ... " << std::flush;
203  }
204 
205  std::shared_ptr<matrix_Type> systemMatrix (new matrix_Type ( uSpace->map() ) );
206 
207  *systemMatrix *= 0.0;
208 
209  if (verbose)
210  {
211  std::cout << " done! " << std::endl;
212  }
213 
214  *systemMatrix *= 0.0;
215 
216  if (verbose)
217  {
218  std::cout << " done! " << std::endl;
219  }
220 
221 
222  // ---------------------------------------------------------------
223  // We start now the assembly of the matrix.
224  // ---------------------------------------------------------------
225 
226  if (verbose)
227  {
228  std::cout << " -- Assembling the Laplace matrix ... " << std::flush;
229  }
230 
231 
232  // ---------------------------------------------------------------
233  // To use the ETA framework, it is mandatory to use a special
234  // namespace, called ExpressionAssembly. This namespace is useful
235  // to avoid collisions with keywords used for the assembly. A
236  // special scope is opened to keep only that part of the code
237  // in the ExpressionAssembly namespace.
238  // ---------------------------------------------------------------
239 
240  {
241  using namespace ExpressionAssembly;
242 
243  // ---------------------------------------------------------------
244  // We can now proceed with assembly. The next instruction
245  // assembles the laplace operator.
246  //
247  // The first argument of the integrate function indicates that the
248  // integration is done on the elements of the mesh located in the
249  // ETFESpace defined earlier.
250  //
251  // The second argument is simply the quadrature rule to be used.
252  //
253  // The third argument is the finite element space of the test
254  // functions.
255  //
256  // The fourth argument is the finite element space of the trial
257  // functions (those used to represent the solution).
258  //
259  // The last argument is the expression to be integrated, i.e.
260  // that represents the weak formulation of the problem. The
261  // keyword phi_i stands for a generic test function and phi_j
262  // a generic trial function. The function grad applied to them
263  // indicates that the gradient is considered and the dot function
264  // indicates a dot product between the two gradients. The
265  // expression to be integrated is then the dot product between
266  // the gradient of the test function and the gradient of the trial
267  // function. This corresponds to the left hand side of the weak
268  // formulation of the Laplace problem.
269  //
270  // Finally, the operator >> indicates that the result of the
271  // integration must be added to the systemMatrix.
272  // ---------------------------------------------------------------
273 
274  integrate ( elements (uSpace->mesh() ),
275  quadRuleTetra4pt,
276  uSpace,
277  uSpace,
278  dot ( grad (phi_i) , grad (phi_j) )
279  )
280  >> systemMatrix;
281  }
282 
283  if (verbose)
284  {
285  std::cout << " done! " << std::endl;
286  }
287 
288 
289  // ---------------------------------------------------------------
290  // As we are already done with the assembly of the matrix, we
291  // finalize it to be able to work on it, e.g. to solve a linear
292  // system.
293  // ---------------------------------------------------------------
294 
295  if (verbose)
296  {
297  std::cout << " -- Closing the matrix ... " << std::flush;
298  }
299 
300  systemMatrix->globalAssemble();
301 
302  if (verbose)
303  {
304  std::cout << " done ! " << std::endl;
305  }
306 
307 
308  // ---------------------------------------------------------------
309  // We compute for this tutorial only the infinity norm of the
310  // matrix for testing purposes.
311  // ---------------------------------------------------------------
312 
313  Real matrixNorm ( systemMatrix->normInf() );
314 
315  if (verbose)
316  {
317  std::cout << " Matrix norm : " << matrixNorm << std::endl;
318  }
319 
320 
321  // ---------------------------------------------------------------
322  // We finalize the MPI session if MPI was used
323  // ---------------------------------------------------------------
324 
325 #ifdef HAVE_MPI
326  MPI_Finalize();
327 #endif
328 
329  // ---------------------------------------------------------------
330  // Finally, we check the norm with respect to a previously
331  // computed one to ensure that it has not changed.
332  // ---------------------------------------------------------------
333 
334  Real matrixNormDiff (std::abs (matrixNorm - 3.2) );
335 
336  if (verbose)
337  {
338  std::cout << " Error : " << matrixNormDiff << std::endl;
339  }
340 
341  if (verbose)
342  {
343  std::cout << " Error : " << matrixNormDiff << std::endl;
344  }
345 
346  Real testTolerance (1e-10);
347 
348  if ( matrixNormDiff < testTolerance )
349  {
350  return ( EXIT_SUCCESS );
351  }
352  return ( EXIT_FAILURE );
353 
354 }
int main(int argc, char **argv)
MatrixEpetra< Real > matrix_Type
double Real
Generic real data.
Definition: LifeV.hpp:175
RegionMesh< LinearTetra > mesh_Type