LifeV
lifev/eta/tutorials/7_ETA_blocks/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 block structures with the ETA framework
30 
31  @author Samuel Quinodoz <samuel.quinodoz@epfl.ch>
32  @date 02-07-2012
33 
34  In this tutorial, we explain how to assemble the linear systems associated
35  with problems with several physical quantities. This is of particular
36  interest for multiphysics problems.
37 
38  In this tutorial, we assemble a Stokes problem and a convection problem
39  using the blocks.
40 
41  Tutorials that should be read before: 1,4
42  */
43 
44 // ---------------------------------------------------------------
45 // We still use the same files, see the previous tutorials for
46 // explanations of the different utilities.
47 //
48 // The only new files are MatrixEpetraStructured.hpp and
49 // VectorEpetraStructured.hpp, that provide the block versions
50 // of MatrixEpetra and VectorEpetra.
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 
69 #include <lifev/core/array/MatrixEpetra.hpp>
70 #include <lifev/core/array/VectorEpetra.hpp>
71 
72 #include <lifev/core/array/MatrixEpetraStructured.hpp>
73 #include <lifev/core/array/VectorEpetraStructured.hpp>
74 
75 #include <lifev/eta/fem/ETFESpace.hpp>
76 #include <lifev/eta/expression/Integrate.hpp>
77 
78 #include <lifev/core/fem/FESpace.hpp>
79 
80 #include <boost/shared_ptr.hpp>
81 
82 // ---------------------------------------------------------------
83 // We work in the LifeV namespace and define the mesh, matrix and
84 // vector types that we will need several times. We add new
85 // typedefs for the block matrices and block vectors.
86 // ---------------------------------------------------------------
87 
88 using namespace LifeV;
89 
91 typedef MatrixEpetra<Real> matrix_Type;
92 typedef VectorEpetra vector_Type;
93 typedef MatrixEpetraStructured<Real> blockMatrix_Type;
94 typedef VectorEpetraStructured blockVector_Type;
95 typedef FESpace<mesh_Type, MapEpetra>::function_Type function_Type;
96 
97 // ---------------------------------------------------------------
98 // We also define a function that is supposed to represent a
99 // force acting on the fluid.
100 // ---------------------------------------------------------------
101 
102 Real forceFctRaw ( const Real& /*t*/, const Real& /*x*/, const Real& /*y*/, const Real& z , const ID& /*i*/)
103 {
104  return z * z;
105 }
106 function_Type forceFct (forceFctRaw);
107 
108 // ---------------------------------------------------------------
109 // As usual, we start by the MPI communicator, the definition of
110 // the mesh and its partitioning.
111 // ---------------------------------------------------------------
112 
113 int main ( int argc, char** argv )
114 {
115 
116 #ifdef HAVE_MPI
117  MPI_Init (&argc, &argv);
118  std::shared_ptr<Epetra_Comm> Comm (new Epetra_MpiComm (MPI_COMM_WORLD) );
119 #else
120  std::shared_ptr<Epetra_Comm> Comm (new Epetra_SerialComm);
121 #endif
122 
123  const bool verbose (Comm->MyPID() == 0);
124 
125 
126  if (verbose)
127  {
128  std::cout << " -- Building and partitioning the mesh ... " << std::flush;
129  }
130 
131  const UInt Nelements (10);
132 
133  std::shared_ptr< mesh_Type > fullMeshPtr (new mesh_Type ( Comm ) );
134 
135  regularMesh3D ( *fullMeshPtr, 1, Nelements, Nelements, Nelements, false,
136  2.0, 2.0, 2.0,
137  -1.0, -1.0, -1.0);
138 
139  std::shared_ptr< mesh_Type > meshPtr;
140  {
141  MeshPartitioner< mesh_Type > meshPart (fullMeshPtr, Comm);
142  meshPtr = meshPart.meshPartition();
143  }
144 
145  fullMeshPtr.reset();
146 
147  if (verbose)
148  {
149  std::cout << " done ! " << std::endl;
150  }
151 
152 
153  // ---------------------------------------------------------------
154  // We define now the ETFESpaces. We need one space for the
155  // velocity (vectorial, P2) and one space for the pressure
156  // (scalar, P1).
157  //
158  // We also define velocity FESpace to use the interpolation.
159  // ---------------------------------------------------------------
160 
161  if (verbose)
162  {
163  std::cout << " -- Building the spaces ... " << std::flush;
164  }
165 
166  std::string uOrder ("P2");
167  std::shared_ptr<FESpace< mesh_Type, MapEpetra > > uSpace
168  ( new FESpace< mesh_Type, MapEpetra > (meshPtr, uOrder, 1, Comm) );
169 
170  std::shared_ptr<ETFESpace< mesh_Type, MapEpetra, 3, 3 > > ETuSpace
171  ( new ETFESpace< mesh_Type, MapEpetra, 3, 3 > (meshPtr, &feTetraP2, & (uSpace->fe().geoMap() ), Comm) );
172 
173  std::shared_ptr<ETFESpace< mesh_Type, MapEpetra, 3, 1 > > ETpSpace
174  ( new ETFESpace< mesh_Type, MapEpetra, 3, 1 > (meshPtr, &feTetraP1, & (uSpace->fe().geoMap() ), Comm) );
175 
176  if (verbose)
177  {
178  std::cout << " done ! " << std::endl;
179  }
180  if (verbose)
181  {
182  std::cout << " ---> Velocity dofs: " << ETuSpace->dof().numTotalDof() << std::endl;
183  }
184  if (verbose)
185  {
186  std::cout << " ---> Pressure dofs: " << ETpSpace->dof().numTotalDof() << std::endl;
187  }
188 
189 
190  // ---------------------------------------------------------------
191  // We want to assemble a Stokes matrix. This matrix is divided
192  // into four blocks (with the (1,1)-block empty). We define it
193  // using a special constructor with "|" operators, which
194  // separates the different blocks.
195  // ---------------------------------------------------------------
196 
197  if (verbose)
198  {
199  std::cout << " -- Assembly of the Stokes matrix ... " << std::flush;
200  }
201 
202  std::shared_ptr<blockMatrix_Type> ETsystemMatrix (new blockMatrix_Type ( ETuSpace->map() | ETpSpace->map() ) );
203  *ETsystemMatrix *= 0.0;
204 
205 
206  // ---------------------------------------------------------------
207  // To fill them, we simply have to call one integrate for each
208  // non-empty block and indicate in which block the contribution
209  // has to go.
210  //
211  // Remark that, depending on the block assembled, the spaces for
212  // the test and trial functions are different.
213  // ---------------------------------------------------------------
214 
215  {
216  using namespace ExpressionAssembly;
217 
218  integrate ( elements (ETuSpace->mesh() ),
219  quadRuleTetra4pt,
220  ETuSpace,
221  ETuSpace,
222 
223  dot ( grad (phi_i) , grad (phi_j) )
224 
225  )
226  >> ETsystemMatrix->block (0, 0);
227 
228  integrate ( elements (ETuSpace->mesh() ),
229  quadRuleTetra4pt,
230  ETuSpace,
231  ETpSpace,
232 
233  phi_j * div (phi_i)
234 
235  )
236  >> ETsystemMatrix->block (0, 1);
237 
238  integrate ( elements (ETuSpace->mesh() ),
239  quadRuleTetra4pt,
240  ETpSpace,
241  ETuSpace,
242 
243  phi_i * div (phi_j)
244 
245  )
246  >> ETsystemMatrix->block (1, 0);
247  }
248 
249  ETsystemMatrix->globalAssemble();
250 
251  if (verbose)
252  {
253  std::cout << " done! " << std::endl;
254  }
255 
256 
257  // ---------------------------------------------------------------
258  // For testing purposes, we also compute the norm of the matrix.
259  // ---------------------------------------------------------------
260 
261  Real matrixNorm (ETsystemMatrix->normInf() );
262 
263  if (verbose)
264  {
265  std::cout << " Matrix norm " << matrixNorm << std::endl;
266  }
267 
268 
269  // ---------------------------------------------------------------
270  // In a very similar way, we can assemble the block right hand
271  // side. Here, we suppose that a force acts on the fluid, so
272  // only the block associated to the velocity is not empty.
273  // ---------------------------------------------------------------
274 
275  if (verbose)
276  {
277  std::cout << " -- Building the rhs ... " << std::flush;
278  }
279 
280  vector_Type fInterpolated (ETuSpace->map(), Repeated);
281 
282  fInterpolated *= 0.0;
283 
284  uSpace->interpolate (forceFct, fInterpolated, 0.0);
285 
286  blockVector_Type ETrhs (ETuSpace->map() | ETpSpace->map() , Repeated);
287  ETrhs *= 0.0;
288 
289  {
290  using namespace ExpressionAssembly;
291 
292  integrate ( elements (ETuSpace->mesh() ),
293  quadRuleTetra4pt,
294  ETuSpace,
295  dot (value (ETuSpace, fInterpolated), phi_i)
296  )
297  >> ETrhs.block (0);
298  }
299 
300  ETrhs.globalAssemble();
301 
302  if (verbose)
303  {
304  std::cout << " done! " << std::endl;
305  }
306 
307 
308  // ---------------------------------------------------------------
309  // For testing purposes, we also compute the norm of the rhs. To
310  // take the norm, we need a unique vector (globalAssemble is not
311  // sufficient).
312  // ---------------------------------------------------------------
313 
314  blockVector_Type ETrhsUnique (ETrhs, Unique);
315 
316  Real rhsNorm (ETrhsUnique.normInf() );
317 
318  if (verbose)
319  {
320  std::cout << " Rhs norm " << rhsNorm << std::endl;
321  }
322 
323 
324  // ---------------------------------------------------------------
325  // We finalize the MPI if needed.
326  // ---------------------------------------------------------------
327 
328 #ifdef HAVE_MPI
329  MPI_Finalize();
330 #endif
331 
332 
333  // ---------------------------------------------------------------
334  // We finally compare the difference with the tolerance of the
335  // test.
336  // ---------------------------------------------------------------
337 
338  if (
339  ( std::abs (matrixNorm - 3.856 ) < 1e-2) &&
340  ( std::abs (rhsNorm - 0.00187384) < 1e-5)
341  )
342  {
343  return ( EXIT_SUCCESS );
344  }
345  return ( EXIT_FAILURE );
346 }
int main(int argc, char **argv)
MatrixEpetra< Real > matrix_Type
function_Type forceFct(forceFctRaw)
Real forceFctRaw(const Real &, const Real &, const Real &, const Real &z, const ID &)
MatrixEpetraStructured< Real > blockMatrix_Type
uint32_type ID
IDs.
Definition: LifeV.hpp:194
double Real
Generic real data.
Definition: LifeV.hpp:175
RegionMesh< LinearTetra > mesh_Type
VectorEpetraStructured blockVector_Type
FESpace< mesh_Type, MapEpetra >::function_Type function_Type