LifeV
navierStokes.hpp
Go to the documentation of this file.
1 /* -*- mode: c++ -*-
2 
3  This file is part of the LifeV Applications.
4 
5  Author(s): Christophe Prud'homme <christophe.prudhomme@epfl.ch>
6  Gwenol Grandperrin <gwenol.grandperrin@epfl.ch>
7  Date: 2011-03-09
8 
9  Copyright (C) 2010 EPFL
10 
11  This program is free software; you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation; either version 2.1 of the License, or
14  (at your option) any later version.
15 
16  This program is distributed in the hope that it will be useful, but
17  WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program; if not, write to the Free Software
23  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24  USA
25 */
26 /*!
27  @file ethiersteiman.hpp
28  @author Christophe Prud'homme <christophe.prudhomme@epfl.ch>
29  @author Gwenol Grandperrin <gwenol.grandperrin@epfl.ch>
30  @date 2011-03-08
31  */
32 
33 #ifndef NAVIERSTOKES_H
34 #define NAVIERSTOKES_H 1
35 
36 #include <lifev/navier_stokes/solver/OseenSolver.hpp>
37 #include <lifev/core/mesh/ElementShapes.hpp>
38 #include <lifev/core/mesh/MeshData.hpp>
39 #include <lifev/core/array/MatrixEpetra.hpp>
40 #include <lifev/core/array/MapEpetra.hpp>
41 #include <lifev/core/mesh/MeshPartitioner.hpp>
42 #include <lifev/core/mesh/MeshData.hpp>
43 #include <lifev/navier_stokes/solver/OseenData.hpp>
44 #include <lifev/core/fem/FESpace.hpp>
45 #include <lifev/navier_stokes/fem/TimeAdvanceBDFNavierStokes.hpp>
46 #include <lifev/core/filter/ExporterEnsight.hpp>
47 #include <lifev/core/filter/ExporterHDF5.hpp>
48 #include <lifev/core/filter/ExporterEmpty.hpp>
49 
50 /*! @enum TimeScheme
51  Order of the BDF
52  */
54 
55 /*!
56  @class NavierStokes
57  @brief NavierStokes Simulation class
58 
59  @author Christophe Prud'homme
60  @author Gwenol Grandperrin
61  @see C.R. Ethier and D.A. Steinman. Exact fully 3D Navier-Stokes solutions for benchmarking. Int. J. Numer. Methods Fluids, 19(5):369-375, 1994
62 
63  This class tests many settings, we propose here a list of the available options.
64  <ul>
65  <li> NavierStokes/test (none/accuracy/space_convergence)
66  <li> NavierStokes/initialization (interpolation/projection)
67  <li> NavierStokes/export_norms
68  <li> NavierStokes/export_exact_solutions
69  <li> NavierStokes/mesh_source (regular_mesh/file)
70  <li> exporter/type (ensight/hdf5)
71  <li> fluid/problem/Re
72  <li> fluid/physics/viscosity
73  <li> fluid/physics/density
74  </ul>
75 
76  In the case of a space convergence test the following options are available
77  <ul>
78  <li> NavierStokes/space_convergence_tolerance
79  <li> fluid/space_discretization/mesh_number
80  <li> fluid/space_discretization/mesh_size
81  <li> fluid/space_discretization/FE_number
82  <li> fluid/space_discretization/vel_order
83  <li> fluid/space_discretization/vel_conv_order_order
84  <li> fluid/space_discretization/press_order
85  <li> fluid/space_discretization/press_conv_order
86  </ul>
87 
88  In the case of an accuracy test the following options are available
89  <ul>
90  <li> NavierStokes/accuracy_tolerance
91  </ul>
92 
93  If the mesh source is a file, the file must be specified in
94  <ul>
95  <li> fluid/space_discretization
96  </ul>
97  */
98 
99 template<typename MeshType, typename Problem>
101 {
102 public:
103  typedef MeshType mesh_Type;
104  typedef Problem problem_Type;
108  typedef typename fluid_Type::vector_Type vector_Type;
110  typedef typename fluid_Type::matrix_Type matrix_Type;
111 
112  /** @name Constructors, destructor
113  */
114  //@{
115 
116  //! Constructor
117  /*!
118  @param argc number of parameter passed through the command line
119  @param argv char passed through the command line
120  */
121  NavierStokes ( int argc,
122  char** argv,
123  const std::string defaultDataName = "data",
124  const std::string outputName = "navierStokes");
125 
126  //! Destructor
128  {}
129 
130  //@}
131 
132  /** @name Methods
133  */
134  //@{
135 
136  //! Launches the simulation
137  void run();
138 
139  //@}
140 
141 
142 private:
143  /*! @enum TestType
144  Order of the BDF
145  */
147 
148  /*! @enum InitializationType
149  Type of initialization. "Interpolation" just interpolates the value of the exact solution to the DoFs.
150  "Projection" solves an Oseen problem where alpha=0, the convective term is linearized by using the exact solution for beta,
151  and the time derivative is passed to the right hand side and computed from the exact solution.
152  */
154 
155  /*! @enum MeshSourceType
156  Type of mesh source. It can be a "File" or a "RegularMesh" which is generated during the simulation
157  */
159 
161  {
162  public:
164  {
165  std::cout << "Some modifications led to changes in the l2 norm of the solution" << std::endl;
166  }
167  };
168 
169  //! Computes the L2 error and the relative L2 error with the exact solution
170  /*!
171  @param velocityAndPressureSolution number of parameter passed through the command line
172  @param uL2Error Variable to store the L2 error for the veloctity
173  @param uRelError Variable to store the Relative L2 error for the velocity
174  @param uFESpace Variable to store the FE space for the velocity
175  @param pL2Error Variable to store the L2 error the pressure
176  @param pRelError Variable to store the Relative L2 error for the pressure
177  @param pFESpace Variable to store the FE space for the pressure
178  @param time Actual timestep of the simulation
179  */
180  void computeErrors (const vector_Type& velocityAndPressureSolution,
181  LifeV::Real& uL2Error, LifeV::Real& uRelError, feSpacePtr_Type& uFESpace,
182  LifeV::Real& pL2Error, LifeV::Real& pRelError, feSpacePtr_Type& pFESpace,
183  LifeV::Real time);
184 
185  //! Method to check the convergence rate of the solution
186  /*!
187  For each type of finite elements the method uses the computed errors obtained with the
188  different meshes to check if the order of convergence follows the theory predictions
189  @param uFELabels Vector containing the FE names for the velocity (e.g. P2, P1Bubble, P1)
190  @param uL2Error Vector containing the computed errors for the velocity
191  @param uConvergenceOrder Vector containing the convergence order corresponding to uFELabel
192  @param pFELabels Vector containing the FE names for the pressure (e.g. P2, P1Bubble, P1)
193  @param pL2Error Vector containing the computed errors for the pressure
194  @param pConvergenceOrder Vector containing the convergence order corresponding to pFELabel
195  @param meshDiscretization Vector containing the subdivisions values used to generate the meshes
196  @param convTolerance Tolerance for the test. The test is passed if (observed convergence)>convTolerance*(theory error prediction)
197  */
198  bool checkConvergenceRate (const std::vector<std::string>& uFELabels,
199  const std::vector<std::vector<LifeV::Real> >& uL2Error,
200  const std::vector<LifeV::UInt>& uConvergenceOrder,
201  const std::vector<std::string>& pFELabels,
202  const std::vector<std::vector<LifeV::Real> > pL2Error,
203  const std::vector<LifeV::UInt>& pConvergenceOrder,
204  const std::vector<LifeV::UInt>& meshDiscretizations,
205  LifeV::Real convTolerance);
206 
207 
208  struct Private;
210 
216 
217  // Test to be performed (accuracy or convergence in space)
219  LifeV::Real M_convTol; // Tolerance of the test (should be <1)
220  // Actually for convTol=1, the test failed
221  // if the improvement of accuracy is less
222  // than predicted by the theory.
223  // convTol lower down the theoretical bounds
225 
226  // Data related to norm export
228  std::ofstream M_outNorm;
229 
230  // Data related to solution export
232 
233  // Initialization method
235 
236  // Mesh source
238 
239  // output file name
240  std::string M_outputName;
241 };
242 
243 
244 using namespace LifeV;
245 
246 //! Null function used to define the boundary conditions
247 /*!
248  @param t Current time
249  @param x x-position
250  @param y y-position
251  @param z z-position
252  @param i ith component of the returned value of the function
253  */
254 Real zero_scalar ( const Real& /* t */,
255  const Real& /* x */,
256  const Real& /* y */,
257  const Real& /* z */,
258  const ID& /* i */ )
259 {
260  return 0.;
261 }
262 
263 
264 //! Parse a string using "," to separate values and return a set of value
265 /*!
266  @param list String containing the list of desired value separated by ","
267  */
269 {
270  std::string stringList = list;
271  std::set<UInt> setList;
272  if ( list == "" )
273  {
274  return setList;
275  }
276  std::string::size_type commaPos = 0;
277  while ( commaPos != std::string::npos )
278  {
279  commaPos = stringList.find ( "," );
280  setList.insert ( atoi ( stringList.substr ( 0, commaPos ).c_str() ) );
281  stringList = stringList.substr ( commaPos + 1 );
282  }
283  setList.insert ( atoi ( stringList.c_str() ) );
284  return setList;
285 }
286 
287 
288 template<typename MeshType, typename Problem>
289 struct NavierStokes<MeshType, Problem>::Private
290 {
292  nu (1),
293  steady (0)
294  {}
295 
296  typedef std::function<Real ( Real const&, Real const&, Real const&, Real const&, ID const& ) > fct_Type;
297 
298  double Re;
299 
300  std::string data_file_name;
301 
302  double nu; /* < viscosity (in m^2/s) */
303  //const double rho; /* < density is constant (in kg/m^3) */
304 
305  bool steady;
307 };
308 
309 template<typename MeshType, typename Problem>
310 NavierStokes<MeshType, Problem>::NavierStokes ( int argc,
311  char** argv,
312  const std::string defaultDataName,
313  const std::string outputName)
314  :
315  M_data ( new Private ),
316  M_outputName (outputName)
317 {
318  GetPot command_line (argc, argv);
319  std::string data_file_name = command_line.follow (defaultDataName.c_str(), 2, "-f", "--file");
320  GetPot dataFile ( data_file_name );
321 
322  M_data->data_file_name = data_file_name;
323 
324  M_data->Re = dataFile ( "fluid/problem/Re", 1. );
325  M_data->nu = dataFile ( "fluid/physics/viscosity", 1. ) /
326  dataFile ( "fluid/physics/density", 1. );
327 
328  // Test type
329  std::string testType = dataFile ("NavierStokes/test", "none");
330  if (testType == "none")
331  {
332  M_test = None;
333  }
334  else if (testType == "accuracy")
335  {
336  M_test = Accuracy;
337  }
338  else if (testType == "space_convergence")
339  {
341  }
342  else
343  {
344  std::cout << "[Error] Unknown test method" << std::endl;
345  exit (1);
346  }
347 
348  M_convTol = dataFile ("NavierStokes/space_convergence_tolerance", 1.0);
349  M_accuracyTol = dataFile ("NavierStokes/accuracy_tolerance", 1.0);
350 
351  // Method of initialization
352  std::string initType = dataFile ("NavierStokes/initialization", "projection");
353  if (initType == "projection")
354  {
356  }
357  else if (initType == "interpolation")
358  {
360  }
361  else
362  {
363  std::cout << "[Error] Unknown initialization method" << std::endl;
364  exit (1);
365  }
366 
367  M_exportNorms = dataFile ("NavierStokes/export_norms", false);
368  M_exportExactSolutions = dataFile ("NavierStokes/export_exact_solutions", false);
369 
370  std::string meshSource = dataFile ( "NavierStokes/mesh_source", "regular_mesh");
371  if (meshSource == "regular_mesh")
372  {
374  }
375  else if (meshSource == "file")
376  {
377  M_meshSource = File;
378  }
379  else
380  {
381  std::cout << "[Error] Unknown mesh source" << std::endl;
382  exit (1);
383  }
384 
385  //Checking the consistency of the data
387  {
388  std::cout << "[Error] You cannot use mesh files to test the space convergence." << std::endl;
389  exit (1);
390  }
391 
392 
393 #ifdef EPETRA_MPI
394 
395  // MPI_Init(&argc,&argv);
396 
397  M_data->comm.reset ( new Epetra_MpiComm ( MPI_COMM_WORLD ) );
398  int ntasks;
399  MPI_Comm_size (MPI_COMM_WORLD, &ntasks);
400 #else
401  M_data->comm.reset ( new Epetra_SerialComm() );
402 #endif
403 
404 }
405 
406 template<typename MeshType, typename Problem>
407 void
408 NavierStokes<MeshType, Problem>::computeErrors (const vector_Type& velocityAndPressureSolution,
409  LifeV::Real& uL2Error, LifeV::Real& uRelError, feSpacePtr_Type& uFESpace,
410  LifeV::Real& pL2Error, LifeV::Real& pRelError, feSpacePtr_Type& pFESpace,
411  LifeV::Real time)
412 {
413  // Computation of the error
414  vector_Type vel (uFESpace->map(), Repeated);
415  vector_Type press (pFESpace->map(), Repeated);
416  vector_Type velpressure ( velocityAndPressureSolution, Repeated );
417 
418  velpressure = velocityAndPressureSolution;
419  vel.subset (velpressure);
420  press.subset (velpressure, uFESpace->dim() *uFESpace->fieldDim() );
421 
422  uL2Error = uFESpace->l2Error (problem_Type::uexact, vel , time, &uRelError );
423  pL2Error = pFESpace->l20Error (problem_Type::pexact, press, time, &pRelError );
424 }
425 
426 template<typename MeshType, typename Problem>
427 bool
428 NavierStokes<MeshType, Problem>::checkConvergenceRate (const std::vector<std::string>& uFELabels,
429  const std::vector<std::vector<LifeV::Real> >& uL2Error,
430  const std::vector<UInt>& uConvergenceOrder,
431  const std::vector<std::string>& pFELabels,
432  const std::vector<std::vector<LifeV::Real> > pL2Error,
433  const std::vector<UInt>& pConvergenceOrder,
434  const std::vector<UInt>& meshDiscretizations,
435  LifeV::Real convTolerance)
436 {
437  // We want to check the convergence of the error and
438  // see if it matches the theory.
439  std::cout << "Checking the convergence:" << std::endl;
440 
441  // Test variable
442  bool success (true); // Variable to keep trace of a previous error
443  Real h1 (0.0), h2 (0.0); // Space discretization step
444  Real uBound (0.0), pBound (0.0); // Velocity and pressure bounds
445  Real uErrRatio (0.0), pErrRatio (0.0); // Ratio of the error E1/E2
446  std::string status (""); // Information string
447 
448  UInt numFELabels (uFELabels.size() );
449  UInt numDiscretizations (meshDiscretizations.size() );
450 
451  for (UInt iFELabel (0); iFELabel < numFELabels; ++iFELabel)
452  {
453  std::cout << " - " << uFELabels[iFELabel] << "-" << pFELabels[iFELabel] << " ... " << std::endl;
454 
455  // Everything is OK a priori
456  status = "OK";
457 
458  for (UInt jDiscretization (0); jDiscretization < numDiscretizations - 1; ++jDiscretization)
459  {
460  h1 = 1.0 / meshDiscretizations[jDiscretization];
461  h2 = 1.0 / meshDiscretizations[jDiscretization + 1];
462 
463  uBound = convTolerance * pow (h1 / h2, int (uConvergenceOrder[iFELabel]) );
464  pBound = convTolerance * pow (h1 / h2, int (pConvergenceOrder[iFELabel]) );
465 
466  uErrRatio = uL2Error[iFELabel][jDiscretization] / uL2Error[iFELabel][jDiscretization + 1]; // E1/E2
467  pErrRatio = pL2Error[iFELabel][jDiscretization] / pL2Error[iFELabel][jDiscretization + 1];
468 
469  if (uErrRatio < uBound)
470  {
471  status = "FAILED";
472  success = false;
473  }
474  if (pErrRatio < pBound)
475  {
476  status = "FAILED";
477  success = false;
478  }
479  std::cout << " " << " (velocity: " << uErrRatio << ">=?" << uBound
480  << ", pressure: " << pErrRatio << ">=?" << pBound << std::endl;
481  }
482  std::cout << " Status: " << status << std::endl;
483 
484  }
485 
486  return success;
487 }
488 
489 template<typename MeshType, typename Problem>
490 void
491 NavierStokes<MeshType, Problem>::run()
492 {
493  bool verbose = (M_data->comm->MyPID() == 0);
494  int nproc;
495  MPI_Comm_size (MPI_COMM_WORLD, &nproc);
496  if (verbose)
497  {
498  std::cout << "[[BEGIN_SIMULATION]]" << std::endl << std::endl;
499 
500  std::cout << "[Initilization of MPI]" << std::endl;
501 #ifdef HAVE_MPI
502  std::cout << "Using MPI (" << nproc << " proc.)" << std::endl;
503 #else
504  std::cout << "Using serial version" << std::endl;
505 #endif
506  }
507 
508  // +-----------------------------------------------+
509  // | Begining of the test |
510  // +-----------------------------------------------+
511  LifeChrono globalChrono;
512  LifeChrono runChrono;
513  LifeChrono initChrono;
514  LifeChrono iterChrono;
515 
516  globalChrono.start();
517  initChrono.start();
518 
519  // +-----------------------------------------------+
520  // | Loading the data |
521  // +-----------------------------------------------+
522  if (verbose)
523  {
524  std::cout << std::endl << "[Loading the data]" << std::endl;
525  }
526  GetPot dataFile ( M_data->data_file_name.c_str() );
527  if (verbose)
528  {
529  switch (M_test)
530  {
531  case Accuracy:
532  std::cout << "Test : checks the accuracy of the solution" << std::endl;
533  break;
534  case SpaceConvergence:
535  std::cout << "Test : checks the convergence in space of the solution" << std::endl;
536  break;
537  case None:
538  break;
539  }
540  }
541  problem_Type::setParamsFromGetPot ( dataFile );
542 
543  UInt numDiscretizations;
544  if ( (M_test == SpaceConvergence) || (M_test == None) )
545  {
546  // Loading the discretization to be tested
547  numDiscretizations = dataFile ( "fluid/space_discretization/mesh_number", 1 );
548  for ( UInt i ( 0 ); i < numDiscretizations; ++i )
549  {
550  M_meshDiscretization.push_back (dataFile ( "fluid/space_discretization/mesh_size", 8, i ) );
551  }
552  }
553  else
554  {
555  M_meshDiscretization.push_back (0); // Just to be sure to have 1 element
556  numDiscretizations = 1;
557  }
558 
559  UInt numFELabels = dataFile ( "fluid/space_discretization/FE_number", 1 );
560  if (M_test == SpaceConvergence)
561  {
562  // Loading the convergence rate for the finite elements tested
563  for ( UInt i ( 0 ); i < numFELabels; ++i )
564  {
565  M_uConvergenceOrder.push_back (dataFile ( "fluid/space_discretization/vel_conv_order", 2, i ) );
566  }
567  for ( UInt i ( 0 ); i < numFELabels; ++i )
568  {
569  M_pConvergenceOrder.push_back (dataFile ( "fluid/space_discretization/press_conv_order", 2, i ) );
570  }
571  }
572 
573  // Loading the Finite element to be tested
574  for ( UInt i ( 0 ); i < numFELabels; ++i )
575  {
576  M_uFELabels.push_back (dataFile ( "fluid/space_discretization/vel_order", "P1", i ) );
577  }
578  for ( UInt i ( 0 ); i < numFELabels; ++i )
579  {
580  M_pFELabels.push_back (dataFile ( "fluid/space_discretization/press_order", "P1", i ) );
581  }
582 
583  // Initialization of the errors array
584  std::vector<std::vector<LifeV::Real> > uL2Error;
585  std::vector<std::vector<LifeV::Real> > pL2Error;
586  uL2Error.clear();
587  pL2Error.clear();
588  std::vector<LifeV::Real> tmpVec (numDiscretizations, 0.0);
589  for (UInt iFELabel (0); iFELabel < numFELabels; ++iFELabel)
590  {
591  uL2Error.push_back (tmpVec);
592  pL2Error.push_back (tmpVec);
593  }
594 
595  initChrono.stop();
596  if (verbose)
597  {
598  std::cout << "Initialization time (pre-run): " << initChrono.diff() << " s." << std::endl;
599  }
600 
601  // Loop on the mesh refinement
602  for (UInt jDiscretization (0); jDiscretization < numDiscretizations; ++jDiscretization)
603  {
604  UInt mElem = M_meshDiscretization[jDiscretization];
605 
606  // Loop on the finite element
607  for (UInt iFELabel (0); iFELabel < numFELabels; ++iFELabel)
608  {
609  if (verbose)
610  {
611  std::cout << std::endl << "[[BEGIN_RUN_" << jDiscretization* numFELabels + iFELabel << "]]" << std::endl;
612  }
613  runChrono.reset();
614  runChrono.start();
615  initChrono.reset();
616  initChrono.start();
617 
618  if (verbose && M_exportNorms)
619  {
620  std::string fileName ("norm_");
621  std::ostringstream oss;
622  oss << mElem;
623  fileName.append (oss.str() );
624  fileName.append ("_");
625  fileName.append (M_uFELabels[iFELabel]);
626  fileName.append (M_pFELabels[iFELabel]);
627  fileName.append (".txt");
628  M_outNorm.open (fileName.c_str() );
629  M_outNorm << "% time / u L2 error / L2 rel error p L2 error / L2 rel error \n" << std::flush;
630  }
631 
632  // +-----------------------------------------------+
633  // | Loading the mesh |
634  // +-----------------------------------------------+
635  if (verbose)
636  {
637  std::cout << "[Loading the mesh]" << std::endl;
638  }
639 
640  std::shared_ptr<mesh_Type > fullMeshPtr ( new mesh_Type ( M_data->comm ) );
641 
642  Int geoDimensions = mesh_Type::S_geoDimensions;
643  // Building the mesh from the source
644  /* if(M_meshSource == RegularMesh) Not yet implemented in 2D
645  {
646  regularMesh3D( *fullMeshPtr,
647  1,
648  mElem, mElem, mElem,
649  false,
650  2.0, 2.0, 2.0,
651  -1.0, -1.0, -1.0);
652 
653  if (verbose) std::cout << "Mesh source: regular mesh("
654  << mElem << "x" << mElem << "x" << mElem << ")" << std::endl;
655  }
656  else */
657  if (M_meshSource == File)
658  {
659  MeshData meshData;
660  meshData.setup (dataFile, "fluid/space_discretization");
661  readMesh (*fullMeshPtr, meshData);
662 
663  if (verbose) std::cout << "Mesh source: file("
664  << meshData.meshDir() << meshData.meshFile() << ")" << std::endl;
665  }
666  else
667  {
668  if (verbose)
669  {
670  std::cout << std::endl << "Error: Unknown source type for the mesh" << std::endl;
671  }
672  exit (1);
673  }
674 
675  if (verbose)
676  {
677  std::cout << "Partitioning the mesh ... " << std::flush;
678  }
679  std::shared_ptr<mesh_Type > localMeshPtr;
680  {
681  MeshPartitioner< mesh_Type > meshPart (fullMeshPtr, M_data->comm);
682  localMeshPtr = meshPart.meshPartition();
683  }
684  fullMeshPtr.reset(); //Freeing the global mesh to save memory
685 
686  // +-----------------------------------------------+
687  // | Creating the FE spaces |
688  // +-----------------------------------------------+
689  if (verbose)
690  {
691  std::cout << std::endl << "[Creating the FE spaces]" << std::endl;
692  }
693  std::string uOrder = M_uFELabels[iFELabel];
694  std::string pOrder = M_pFELabels[iFELabel];
695 
696  if (verbose) std::cout << "FE for the velocity: " << uOrder << std::endl
697  << "FE for the pressure: " << pOrder << std::endl;
698 
699  if (verbose)
700  {
701  std::cout << "Building the velocity FE space ... " << std::flush;
702  }
703  feSpacePtr_Type uFESpace;
704  uFESpace.reset (new feSpace_Type (localMeshPtr, uOrder, geoDimensions, M_data->comm) );
705  if (verbose)
706  {
707  std::cout << "ok." << std::endl;
708  }
709 
710  if (verbose)
711  {
712  std::cout << "Building the pressure FE space ... " << std::flush;
713  }
714  feSpacePtr_Type pFESpace;
715  pFESpace.reset (new feSpace_Type (localMeshPtr, pOrder, 1, M_data->comm) );
716  if (verbose)
717  {
718  std::cout << "ok." << std::endl;
719  }
720 
721  UInt totalVelDof = uFESpace->dof().numTotalDof();
722  UInt totalPressDof = pFESpace->dof().numTotalDof();
723 
724  // Pressure offset in the vector
725  UInt pressureOffset = uFESpace->fieldDim() * uFESpace->dof().numTotalDof();
726 
727  if (verbose)
728  {
729  std::cout << "Total Velocity Dof = " << totalVelDof << std::endl;
730  }
731  if (verbose)
732  {
733  std::cout << "Total Pressure Dof = " << totalPressDof << std::endl;
734  }
735 
736  // +-----------------------------------------------+
737  // | Boundary conditions |
738  // +-----------------------------------------------+
739  if (verbose)
740  {
741  std::cout << std::endl << "[Boundary conditions]" << std::endl;
742  }
743  std::string dirichletList = dataFile ( "fluid/problem/dirichletList", "" );
744  std::set<UInt> dirichletMarkers = parseList ( dirichletList );
745  std::string neumannList = dataFile ( "fluid/problem/neumannList", "" );
746  std::set<UInt> neumannMarkers = parseList ( neumannList );
747 
748  BCHandler bcH;
749  BCFunctionBase uWall ( problem_Type::uexact );
750  BCFunctionBase uNeumann ( problem_Type::fNeumann );
751 
752  for (std::set<UInt>::const_iterator it = dirichletMarkers.begin();
753  it != dirichletMarkers.end(); ++it)
754  {
755  bcH.addBC ( "Wall", *it, Essential, Full, uWall, geoDimensions );
756  }
757  for (std::set<UInt>::const_iterator it = neumannMarkers.begin();
758  it != neumannMarkers.end(); ++it)
759  {
760  bcH.addBC ( "Flux", *it, Natural, Full, uNeumann, geoDimensions );
761  }
762 
763  // If we change the FE we have to update the BCHandler (internal data)
764  bcH.bcUpdate ( *localMeshPtr, uFESpace->feBd(), uFESpace->dof() );
765 
766  // +-----------------------------------------------+
767  // | Creating the problem |
768  // +-----------------------------------------------+
769  if (verbose)
770  {
771  std::cout << std::endl << "[Creating the problem]" << std::endl;
772  }
773  std::shared_ptr<OseenData> oseenData (new OseenData() );
774  oseenData->setup ( dataFile );
775 
776  if (verbose)
777  {
778  std::cout << "Time discretization order " << oseenData->dataTimeAdvance()->orderBDF() << std::endl;
779  }
780 
781  OseenSolver< mesh_Type > fluid (oseenData,
782  *uFESpace,
783  *pFESpace,
784  M_data->comm);
785 
786  MapEpetra fullMap (fluid.getMap() );
787 
788  fluid.setUp (dataFile);
789  fluid.buildSystem();
790 
791  MPI_Barrier (MPI_COMM_WORLD);
792 
793  // +-----------------------------------------------+
794  // | Initialization of the simulation |
795  // +-----------------------------------------------+
796  if (verbose)
797  {
798  std::cout << std::endl << "[Initialization of the simulation]" << std::endl;
799  }
800  Real dt = oseenData->dataTime()->timeStep();
801  Real t0 = oseenData->dataTime()->initialTime();
802  Real tFinal = oseenData->dataTime()->endTime();
803 
804 
805  // bdf object to store the previous solutions
807  bdf.setup (oseenData->dataTimeAdvance()->orderBDF() );
808 
809  /*
810  Initialization with exact solution: either interpolation or "L2-NS"-projection
811  Depending on which order scheme we want for the time derivative, we need a to
812  setup a fixed number of solution required by the scheme. Therefore we need to
813  compute the solution for some timestep before t0.
814  */
815  t0 -= dt * bdf.bdfVelocity().order();
816 
817  if (verbose)
818  {
819  std::cout << "Computing the initial solution ... " << std::endl;
820  }
821 
822  vector_Type beta ( fullMap );
823  vector_Type rhs ( fullMap );
824 
825  MPI_Barrier (MPI_COMM_WORLD);
826 
827  oseenData->dataTime()->setTime (t0);
828  fluid.initialize ( problem_Type::uexact, problem_Type::pexact );
829 
830  bdf.bdfVelocity().setInitialCondition ( *fluid.solution() );
831 
832  /*
833  Initial solution loading (interpolation or projection)
834  This part of the code take advantage of the fact that the Projection
835  method adds only a few lines to the Interpolation initialization method.
836  First notice that the loop ensure that enough solutions are computed in
837  order to use the BDF scheme chose previously.
838 
839  Interpolation case:
840  We start by setting the current time then we initialize the OseenSolver
841  using fluid.initialize. Therefore the exact solution is interpolated to
842  obtain a solution. Then we store this solution for the BDF scheme using
843  bdf.bdfVelocity().shiftRight(...).
844 
845  Projection case:
846  In that case the solution obtained in fluid.initialize is used as a starting
847  point to solve the steady-state problem:
848  \Delta u + u^*\nabla u +\nabla p = -(\frace{\partial u}{\partial t})^*
849  where the * means that the value is obtained by interpolating the quantity
850  using the exact solution.
851  */
852  Real time = t0 + dt;
853  for ( ; time <= oseenData->dataTime()->initialTime() + dt / 2.; time += dt)
854  {
855 
856  oseenData->dataTime()->setTime (time);
857 
858  beta *= 0.;
859  rhs *= 0.;
860 
861  fluid.initialize ( problem_Type::uexact, problem_Type::pexact );
862 
863  beta = *fluid.solution();
864 
865  if (M_initMethod == Projection)
866  {
867  uFESpace->interpolate ( static_cast<typename feSpace_Type::function_Type> ( problem_Type::uderexact ), rhs, time);
868  rhs *= -1.;
869  rhs = fluid.matrixMass() * rhs;
870  fluid.updateSystem ( 0., beta, rhs );
871  fluid.iterate (bcH);
872  }
873 
874  // Computation of the error
875  LifeV::Real urelerr, prelerr, ul2error, pl2error;
876 
877  computeErrors (*fluid.solution(),
878  ul2error, urelerr, uFESpace,
879  pl2error, prelerr, pFESpace,
880  time);
881 
882  if (verbose && M_exportNorms)
883  {
884  M_outNorm << time << " "
885  << ul2error << " "
886  << urelerr << " "
887  << pl2error << " "
888  << prelerr << "\n" << std::flush;
889  }
890 
891 
892  // Updating bdf
893  bdf.bdfVelocity().shiftRight ( *fluid.solution() );
894 
895  }
896 
897  fluid.resetPreconditioner();
898 
899  std::shared_ptr< Exporter<mesh_Type > > exporter;
900 
901  vectorPtr_Type velAndPressure;
902  // only for export -->
903  vectorPtr_Type exactPressPtr;
904  vector_Type exactPress (pFESpace->map(), Repeated);
905  vectorPtr_Type exactVelPtr;
906  vector_Type exactVel (uFESpace->map(), Repeated);
907  // <--
908 
909  std::string const exporterType = dataFile ( "exporter/type", "ensight");
910 
911 #ifdef HAVE_HDF5
912  if (exporterType.compare ("hdf5") == 0)
913  {
914  exporter.reset ( new ExporterHDF5<mesh_Type > ( dataFile, M_outputName ) );
915  exporter->setPostDir ( "./" ); // This is a test to see if M_post_dir is working
916  exporter->setMeshProcId ( localMeshPtr, M_data->comm->MyPID() );
917  }
918  else
919 #endif
920  {
921  if (exporterType.compare ("none") == 0)
922  {
923  exporter.reset ( new ExporterEmpty<mesh_Type > ( dataFile, localMeshPtr, M_outputName, M_data->comm->MyPID() ) );
924  }
925  else
926  {
927  exporter.reset ( new ExporterEnsight<mesh_Type > ( dataFile, localMeshPtr, M_outputName, M_data->comm->MyPID() ) );
928  }
929  }
930 
931  velAndPressure.reset ( new vector_Type (*fluid.solution(), exporter->mapType() ) );
933  {
934  exactPressPtr.reset ( new vector_Type (exactPress, exporter->mapType() ) );
935  pFESpace->interpolate ( static_cast<typename feSpace_Type::function_Type> ( problem_Type::pexact ), *exactPressPtr, 0 );
936  exactVelPtr.reset ( new vector_Type (exactVel, exporter->mapType() ) );
937  uFESpace->interpolate ( static_cast<typename feSpace_Type::function_Type> ( problem_Type::uexact ), *exactVelPtr, 0 );
938  }
939 
940  exporter->addVariable ( ExporterData<mesh_Type>::VectorField, "velocity", uFESpace,
941  velAndPressure, UInt (0) );
942  exporter->addVariable ( ExporterData<mesh_Type>::ScalarField, "pressure", pFESpace,
943  velAndPressure, pressureOffset );
945  {
946  exporter->addVariable ( ExporterData<mesh_Type>::VectorField, "exactVelocity", uFESpace,
947  exactVelPtr, UInt (0) );
948  exporter->addVariable ( ExporterData<mesh_Type>::ScalarField, "exactPressure", pFESpace,
949  exactPressPtr, UInt (0) );
950  }
951  exporter->postProcess ( 0 );
952 
953  initChrono.stop();
954  if (verbose)
955  {
956  std::cout << "Initialization time: " << initChrono.diff() << " s." << std::endl;
957  }
958 
959  // +-----------------------------------------------+
960  // | Solving the problem |
961  // +-----------------------------------------------+
962  if (verbose)
963  {
964  std::cout << std::endl << "[Solving the problem]" << std::endl;
965  }
966  int iter = 1;
967 
968  for ( ; time <= tFinal + dt / 2.; time += dt, iter++)
969  {
970  iterChrono.reset();
971  iterChrono.start();
972 
973  oseenData->dataTime()->setTime (time);
974 
975  if (verbose)
976  {
977  std::cout << "[t = " << oseenData->dataTime()->time() << " s.]" << std::endl;
978  }
979 
980  double alpha = bdf.bdfVelocity().coefficientFirstDerivative ( 0 ) / oseenData->dataTime()->timeStep();
981 
982  bdf.bdfVelocity().extrapolation (beta); // Extrapolation for the convective term
983  bdf.bdfVelocity().updateRHSContribution ( oseenData->dataTime()->timeStep() );
984 
985  fluid.getDisplayer().leaderPrint ("alpha ", alpha);
986  fluid.getDisplayer().leaderPrint ("\n");
987  fluid.getDisplayer().leaderPrint ("norm beta ", beta.norm2() );
988  fluid.getDisplayer().leaderPrint ("\n");
989  fluid.getDisplayer().leaderPrint ("norm rhs ", rhs.norm2() );
990  fluid.getDisplayer().leaderPrint ("\n");
991 
992  if (oseenData->conservativeFormulation() )
993  {
994  rhs = fluid.matrixMass() * bdf.bdfVelocity().rhsContributionFirstDerivative();
995  }
996 
997  fluid.updateSystem ( alpha, beta, rhs );
998 
999  if (!oseenData->conservativeFormulation() )
1000  {
1001  rhs = fluid.matrixMass() * bdf.bdfVelocity().rhsContributionFirstDerivative();
1002  }
1003 
1004  fluid.iterate ( bcH );
1005 
1006  bdf.bdfVelocity().shiftRight ( *fluid.solution() );
1007 
1008  // Computation of the error
1009  LifeV::Real urelerr, prelerr, ul2error, pl2error;
1010 
1011  computeErrors (*fluid.solution(),
1012  ul2error, urelerr, uFESpace,
1013  pl2error, prelerr, pFESpace,
1014  time);
1015 
1016  if (verbose && M_exportNorms)
1017  {
1018  M_outNorm << time << " "
1019  << ul2error << " "
1020  << urelerr << " "
1021  << pl2error << " "
1022  << prelerr << "\n" << std::flush;
1023  }
1024 
1025  // Saving the errors for the final test
1026  uL2Error[iFELabel][jDiscretization] = ul2error;
1027  pL2Error[iFELabel][jDiscretization] = pl2error;
1028 
1029  // Exporting the solution
1030  *velAndPressure = *fluid.solution();
1032  {
1033  pFESpace->interpolate ( static_cast<typename feSpace_Type::function_Type> ( problem_Type::pexact ), *exactPressPtr, time );
1034  uFESpace->interpolate ( static_cast<typename feSpace_Type::function_Type> ( problem_Type::uexact ), *exactVelPtr, time );
1035  }
1036  exporter->postProcess ( time );
1037 
1038 
1039  MPI_Barrier (MPI_COMM_WORLD);
1040 
1041  iterChrono.stop();
1042  if (verbose)
1043  {
1044  std::cout << "Iteration time: " << initChrono.diff() << " s." << std::endl << std::endl;
1045  }
1046  }
1047 
1048  if (verbose && M_exportNorms)
1049  {
1050  M_outNorm.close();
1051  }
1052 
1053  // ** BEGIN Accuracy test **
1054  if (M_test == Accuracy)
1055  {
1056  // Computation of the error
1057  LifeV::Real urelerr, prelerr, ul2error, pl2error;
1058 
1059  computeErrors (*fluid.solution(),
1060  ul2error, urelerr, uFESpace,
1061  pl2error, prelerr, pFESpace,
1062  time);
1063 
1064  if (verbose) std::cout << "Relative error: E(u)=" << urelerr << ", E(p)=" << prelerr << std::endl
1065  << "Tolerance=" << M_accuracyTol << std::endl;
1066 
1067  if (urelerr > M_accuracyTol || prelerr > M_accuracyTol)
1068  {
1069  if (verbose)
1070  {
1071  std::cout << "TEST_NAVIERSTOKES STATUS: ECHEC" << std::endl;
1072  }
1073  throw typename NavierStokes::RESULT_CHANGED_EXCEPTION();
1074  }
1075  }
1076  // ** END Accuracy test **
1077 
1078  runChrono.stop();
1079  if (verbose)
1080  {
1081  std::cout << "Total run time: " << runChrono.diff() << " s." << std::endl;
1082  }
1083  if (verbose)
1084  {
1085  std::cout << "[[END_RUN_" << jDiscretization* numFELabels + iFELabel << "]]" << std::endl;
1086  }
1087 
1088  } // End of loop on the finite elements
1089  } // End of loop on the mesh refinement
1090 
1091  // ** BEGIN Space convergence test **
1092  if (verbose && (M_test == SpaceConvergence) )
1093  {
1094  bool success;
1095  success = checkConvergenceRate (M_uFELabels, uL2Error, M_uConvergenceOrder,
1096  M_pFELabels, pL2Error, M_pConvergenceOrder,
1097  M_meshDiscretization,
1098  M_convTol);
1099 
1100  if (!success)
1101  {
1102  if (verbose)
1103  {
1104  std::cout << "TEST_NAVIERSTOKES STATUS: ECHEC" << std::endl;
1105  }
1106  throw typename NavierStokes::RESULT_CHANGED_EXCEPTION();
1107  }
1108  }
1109  // ** END Space convergence test **
1110  globalChrono.stop();
1111  if (verbose)
1112  {
1113  std::cout << std::endl << "Total simulation time:" << globalChrono.diff() << " s." << std::endl;
1114  }
1115  if (verbose && (M_test != None) )
1116  {
1117  std::cout << "TEST_NAVIERSTOKES_STATUS: SUCCESS" << std::endl;
1118  }
1119  if (verbose)
1120  {
1121  std::cout << std::endl << "[[END_SIMULATION]]" << std::endl;
1122  }
1123 }
1124 
1125 #endif /* NAVIERSTOKES_H */
fluid_Type::matrix_Type matrix_Type
void start()
Start the timer.
Definition: LifeChrono.hpp:93
~NavierStokes()
Destructor.
MeshType mesh_Type
std::function< Real(Real const &, Real const &, Real const &, Real const &, ID const &) > fct_Type
LifeV::OseenSolver< mesh_Type > fluid_Type
Problem problem_Type
GetPot(const int argc_, char **argv_, const char *FieldSeparator=0x0)
Definition: GetPot.hpp:507
BCHandler - class for handling boundary conditions.
Definition: BCHandler.hpp:100
void run()
Launches the simulation.
MeshSourceType M_meshSource
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
std::vector< std::string > M_uFELabels
LifeV::Real M_convTol
LifeV::Real M_accuracyTol
std::set< UInt > parseList(const std::string &list)
BCFunctionBase - class that holds the function used for prescribing boundary conditions.
Definition: BCFunction.hpp:77
Epetra_Import const & importer()
Getter for the Epetra_Import.
Definition: MapEpetra.cpp:394
std::shared_ptr< feSpace_Type > feSpacePtr_Type
std::shared_ptr< vector_Type > vectorPtr_Type
uint32_type ID
IDs.
Definition: LifeV.hpp:194
NavierStokes(int argc, char **argv, const std::string defaultDataName="data", const std::string outputName="navierStokes")
Constructor.
NavierStokes Simulation class.
void computeErrors(const vector_Type &velocityAndPressureSolution, LifeV::Real &uL2Error, LifeV::Real &uRelError, feSpacePtr_Type &uFESpace, LifeV::Real &pL2Error, LifeV::Real &pRelError, feSpacePtr_Type &pFESpace, LifeV::Real time)
Computes the L2 error and the relative L2 error with the exact solution.
std::vector< LifeV::UInt > M_pConvergenceOrder
MeshData - class for handling spatial discretization.
Definition: MeshData.hpp:72
InitializationType M_initMethod
double Real
Generic real data.
Definition: LifeV.hpp:175
int operator()(const char *VarName, int Default) const
Definition: GetPot.hpp:2021
TestType M_test
std::vector< LifeV::UInt > M_meshDiscretization
std::vector< std::string > M_pFELabels
bool M_exportExactSolutions
std::string M_outputName
const std::string operator()(const char *VarName, const char *Default) const
Definition: GetPot.hpp:2045
void stop()
Stop the timer.
Definition: LifeChrono.hpp:100
GetPot(const STRING_VECTOR &FileNameList)
Definition: GetPot.hpp:645
bool operator()(const char *VarName, bool Default) const
Definition: GetPot.hpp:2008
bool checkConvergenceRate(const std::vector< std::string > &uFELabels, const std::vector< std::vector< LifeV::Real > > &uL2Error, const std::vector< LifeV::UInt > &uConvergenceOrder, const std::vector< std::string > &pFELabels, const std::vector< std::vector< LifeV::Real > > pL2Error, const std::vector< LifeV::UInt > &pConvergenceOrder, const std::vector< LifeV::UInt > &meshDiscretizations, LifeV::Real convTolerance)
Method to check the convergence rate of the solution.
std::shared_ptr< Epetra_Comm > comm
LifeV::FESpace< mesh_Type, LifeV::MapEpetra > feSpace_Type
std::string data_file_name
fluid_Type::vector_Type vector_Type
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191
std::shared_ptr< Private > M_data
std::vector< LifeV::UInt > M_uConvergenceOrder
std::ofstream M_outNorm