LifeV
lifev/fsi/testsuite/fsi_monolithic/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 File containing the Monolithic Test
30  *
31  * @date 2009-04-09
32  * @author Paolo Crosetto <crosetto@iacspc70.epfl.ch>
33  *
34  * @maintainer Paolo Crosetto <crosetto@iacspc70.epfl.ch>
35  *
36  * Monolithic problem. Features:
37  * - fullMonolithic (CE):
38  * -# solution with exact Newton (semiImplicit = false, useShapeDerivatives = true, conservativeFormulation = false)
39  * -# solution with quasi Newton (semiImplicit = false, useShapeDerivatives = true, conservativeFormulation = false)
40  * -# preconditioner choice: see the classes Monolithic and fullMonolithic
41  * - Monolithic (GCE):
42  * -# solution extrapolating the fluid domain (semiImplicit = false, useShapeDerivatives = true, conservativeFormulation = false)
43  * -# preconditioner choice: see the classes Monolithic and fullMonolithic
44  * - boundary conditions:
45  * -# Neumann
46  * -# Dirichlet
47  * -# Robin
48  * -# Fluxes (defective)
49  * -# absorbing \cite BadiaNobileVergara2008 :
50  * through the class flowConditions.
51  * - optional: computation of wall shear stress (not properly tested in parallel)
52  * - optional: computation of the largest singular values of the preconditioned matrix
53  *
54  * \b Features:
55  * This test by default solves the FSI probem discretized in time using the GCE or CE methods, implemented respectively
56  * in the files monolithicGE.hpp and monolithicGI.hpp . The geometry is that of a tube (benchmark test introduced in \cite Gerbeau2003).
57  * In this test the boundary conditions assigned are of type:
58  * - flux (defective b.c.) at the inlet
59  * - absorbing (see \cite BadiaNobileVergara2008) at the outlet
60  * - Robin b.c. on the solid external wall
61  * - Dirichlet homogeneous at the solid rings on the inlet-outlet (clamped tube).
62  *
63  * The output is written at every timestep, in HDF5 (if available) or ensight format.
64  * This test implements an inlet flux bundary condition for the first three time steps, then at the fourth time step
65  * the inlet boundary condition is replaced by a Neumann one (this mechanism is useful to implement rudimental valves).
66  * The outflow boundary condition is of absorbing type. At the outer wall for the structure a Robin condition is imposed.
67  * The time discretization is carried out using BDF methods of order 2. At the moment, even is the Newmark method is available
68  * for the temporal discretization of the single problems( e.g. in test_structuralsolver), it cannot be used in the FSI framework
69  * since the class TimeAdvanceNewmark is not registered as one of the possible instances of the abstrac class TimeAdvance.
70  */
71 
72 
73 #include <cassert>
74 #include <cstdlib>
75 
76 #include <boost/timer.hpp>
77 
78 #include <Epetra_ConfigDefs.h>
79 #ifdef EPETRA_MPI
80 #include <mpi.h>
81 #include <Epetra_MpiComm.h>
82 #else
83 #include <Epetra_SerialComm.h>
84 #endif
85 
86 
87 // LifeV includes
88 #include <lifev/core/fem/BCHandler.hpp>
89 #include <lifev/core/LifeV.hpp>
90 
91 #include <lifev/core/algorithm/PreconditionerIfpack.hpp>
92 #include <lifev/core/algorithm/PreconditionerML.hpp>
93 
94 #include <lifev/fsi/solver/FSISolver.hpp>
95 #include <lifev/structure/solver/StructuralOperator.hpp>
96 #include <lifev/fsi/solver/FSIMonolithicGI.hpp>
97 
98 #include <lifev/core/filter/ExporterEnsight.hpp>
99 #include <lifev/core/filter/ExporterEmpty.hpp>
100 #ifdef HAVE_HDF5
101 #include <lifev/core/filter/ExporterHDF5.hpp>
102 #endif
103 
104 #include "ud_functions.hpp"
106 #include "flowConditions.hpp"
107 #include "lumpedHeart.hpp"
108 
109 
110 class Problem
111 {
112 public:
113 
115 
116  typedef LifeV::FSIOperator::data_Type data_Type;
117  typedef LifeV::FSIOperator::dataPtr_Type dataPtr_Type;
118 
119  typedef LifeV::FSIOperator::vector_Type vector_Type;
120  typedef LifeV::FSIOperator::vectorPtr_Type vectorPtr_Type;
121 
123 
124  typedef LifeV::ExporterEnsight<LifeV::FSIOperator::mesh_Type> ensightFilter_Type;
126 #ifdef HAVE_HDF5
129 #endif
131  /*!
132  This routine sets up the problem:
133 
134  -# create the standard boundary conditions for the fluid and
135  structure problems.
136 
137  -# initialize and setup the FSIsolver
138  */
139 
140  Problem ( GetPot const& data_file ) :
141  M_Tstart (0.),
142  M_saveEvery (1),
143  M_returnValue (EXIT_FAILURE)
144 
145  {
146  using namespace LifeV;
147 
148  FSIOperator::solid_Type::material_Type::isotropicLaw_Type::StructureIsotropicMaterialFactory::instance().registerProduct ( "linearVenantKirchhoff", &FSIOperator::createVenantKirchhoffLinear );
149  FSIOperator::solid_Type::material_Type::isotropicLaw_Type::StructureIsotropicMaterialFactory::instance().registerProduct ( "exponential", &FSIOperator::createExponentialMaterialNonLinear );
150  FSIOperator::solid_Type::material_Type::isotropicLaw_Type::StructureIsotropicMaterialFactory::instance().registerProduct ( "neoHookean", &FSIOperator::createNeoHookeanMaterialNonLinear );
151  FSIOperator::solid_Type::material_Type::isotropicLaw_Type::StructureIsotropicMaterialFactory::instance().registerProduct ( "nonLinearVenantKirchhoff", &FSIOperator::createVenantKirchhoffNonLinear );
152 
153  std::cout << "register MonolithicGE : " << FSIMonolithicGE::S_register << std::endl;
154  std::cout << "register MonolithicGI : " << FSIMonolithicGI::S_register << std::endl;
155 
156  M_data = dataPtr_Type ( new data_Type() );
157  M_data->setup ( data_file );
158  //M_data->dataSolid()->setTimeData( M_data->dataFluid()->dataTime() ); //Same TimeData for fluid & solid
159  //M_data->showMe();
160 
161  M_fsi = fsi_solver_ptr ( new FSISolver( ) );
162  MPI_Barrier ( MPI_COMM_WORLD );
163 
164  M_fsi->setData ( M_data );
165  M_fsi->FSIOper()->setDataFile ( data_file ); //TO BE REMOVED!
166 
167  // Setting FESpace and DOF
168 
169  std::string fluidMeshPartitioned = data_file ( "problem/fluidMeshPartitioned", "none" );
170  std::string solidMeshPartitioned = data_file ( "problem/solidMeshPartitioned", "none" );
171 #ifdef HAVE_HDF5
172  if ( fluidMeshPartitioned.compare ( "none" ) )
173  {
174  FSIOperator::meshFilter_Type fluidMeshFilter ( data_file, fluidMeshPartitioned );
175  fluidMeshFilter.setComm ( M_fsi->FSIOper()->worldComm() );
176  FSIOperator::meshFilter_Type solidMeshFilter ( data_file, solidMeshPartitioned );
177  solidMeshFilter.setComm ( M_fsi->FSIOper( )->worldComm( ) );
178  M_fsi->FSIOper( )->partitionMeshes ( fluidMeshFilter, solidMeshFilter );
179  M_fsi->FSIOper( )->setupFEspace( );
180  M_fsi->FSIOper( )->setupDOF ( fluidMeshFilter );
181  fluidMeshFilter.closeFile( );
182  solidMeshFilter.closeFile( );
183  }
184  else
185 #endif
186  {
187  M_fsi->FSIOper( )->partitionMeshes( );
188  M_fsi->FSIOper( )->setupFEspace( );
189  M_fsi->FSIOper( )->setupDOF( );
190  }
191 
192  debugStream ( 10000 ) << "Setting up the FESpace and DOF \n";
193 
194  MPI_Barrier ( MPI_COMM_WORLD );
195 
196 #ifdef DEBUG
197  debugStream ( 10000 ) << "Setting up the BC \n";
198 #endif
199  M_fsi->setFluidBC ( BCh_monolithicFlux ( true ) );
200  M_fsi->setSolidBC ( BCh_monolithicSolid ( *M_fsi->FSIOper( ) ) );
201 
202  M_fsi->setup();
203 
204  M_fsi->setFluidBC ( BCh_monolithicFluid ( *M_fsi->FSIOper( ), true ) );
205  M_fsi->setHarmonicExtensionBC ( BCh_harmonicExtension ( *M_fsi->FSIOper( ) ) );
206 
207  dynamic_cast<LifeV::FSIMonolithic*> (M_fsi->FSIOper().get() )->mergeBCHandlers();
208 
209 #ifdef DEBUG
210  debugStream ( 10000 ) << "BC set\n";
211 #endif
212 
213  std::string const exporterType = data_file ( "exporter/type", "ensight" );
214  std::string const fluidName = data_file ( "exporter/fluid/filename", "fluid" );
215  std::string const solidName = data_file ( "exporter/solid/filename", "solid" );
216 
217 #ifdef HAVE_HDF5
218  if (exporterType.compare ("hdf5") == 0)
219  {
220  M_exporterFluid.reset ( new hdf5Filter_Type ( data_file, fluidName) );
221  M_exporterSolid.reset ( new hdf5Filter_Type ( data_file, solidName) );
222  }
223  else
224 #endif
225  {
226  if (exporterType.compare ("none") == 0)
227  {
228  M_exporterFluid.reset ( new ExporterEmpty<RegionMesh<LinearTetra> > ( data_file, M_fsi->FSIOper()->uFESpace().mesh(), fluidName, M_fsi->FSIOper()->uFESpace().map().comm().MyPID() ) );
229  M_exporterSolid.reset ( new ExporterEmpty<RegionMesh<LinearTetra> > ( data_file, M_fsi->FSIOper()->dFESpace().mesh(), solidName, M_fsi->FSIOper()->uFESpace().map().comm().MyPID() ) );
230  }
231  else
232  {
233  M_exporterFluid.reset ( new ensightFilter_Type ( data_file, fluidName) );
234  M_exporterSolid.reset ( new ensightFilter_Type ( data_file, solidName) );
235  }
236  }
237 
238 
239  // load using ensight/hdf5
240  M_saveEvery = data_file ("exporter/saveEvery", 1);
241 
242  M_fsi->initializeMonolithicOperator();
243 
244  M_velAndPressure.reset ( new vector_Type ( M_fsi->FSIOper()->fluid().getMap(), M_exporterFluid->mapType() ) );
245 
246  M_fluidDisp.reset ( new vector_Type ( M_fsi->FSIOper()->mmFESpace().map(), M_exporterFluid->mapType() ) );
247 
248  M_solidDisp.reset ( new vector_Type ( M_fsi->FSIOper()->dFESpace().map(), M_exporterSolid->mapType() ) );
249 
250  M_exporterFluid->setMeshProcId (M_fsi->FSIOper()->uFESpace().mesh(), M_fsi->FSIOper()->uFESpace().map().comm().MyPID() );
251  M_exporterSolid->setMeshProcId (M_fsi->FSIOper()->dFESpace().mesh(), M_fsi->FSIOper()->dFESpace().map().comm().MyPID() );
252  M_exporterFluid->addVariable ( ExporterData<FSIOperator::mesh_Type>::VectorField, "f-velocity",
253  M_fsi->FSIOper()->uFESpacePtr(), M_velAndPressure, UInt (0) );
254  M_exporterFluid->addVariable ( ExporterData<FSIOperator::mesh_Type>::ScalarField, "f-pressure",
255  M_fsi->FSIOper()->pFESpacePtr(), M_velAndPressure,
256  UInt (3 * M_fsi->FSIOper()->uFESpace().dof().numTotalDof() ) );
257 
258  M_exporterFluid->addVariable ( ExporterData<FSIOperator::mesh_Type>::VectorField, "f-displacement",
259  M_fsi->FSIOper()->mmFESpacePtr(), M_fluidDisp, UInt (0) );
260 
261 
262 
263 
264  M_exporterSolid->addVariable ( ExporterData<FSIOperator::mesh_Type>::VectorField, "s-displacement",
265  M_fsi->FSIOper()->dFESpacePtr(), M_solidDisp, UInt (0) );
266 
267  //M_fsi->FSIOper()->fluid().setupPostProc(); //this has to be called if we want to initialize the postProcess
268 
269  FC0.initParameters ( *M_fsi->FSIOper(), 3);
270  LH.initParameters ( *M_fsi->FSIOper(), "dataHM");
271 
272  M_data->dataFluid()->dataTime()->setInitialTime ( M_Tstart );
273  M_data->dataFluid()->dataTime()->setTime ( M_data->dataFluid()->dataTime()->initialTime() );
274  M_data->dataSolid()->dataTime()->setInitialTime ( M_Tstart );
275  M_data->dataSolid()->dataTime()->setTime ( M_data->dataFluid()->dataTime()->initialTime() );
276  M_data->timeDataALE()->setInitialTime ( M_Tstart );
277  M_data->timeDataALE()->setTime ( M_data->dataFluid()->dataTime()->initialTime() );
278  }
279 
280  /*!
281  This routine runs the temporal loop
282  */
283  int
284  run()
285  {
286  boost::timer _overall_timer;
287 
288  LifeV::UInt iter = 1;
289  //LifeV::UInt offset=dynamic_cast<LifeV::FSIMonolithic*>(M_fsi->FSIOper().get())->offset();
290 
291  dynamic_cast<LifeV::FSIMonolithic*> (M_fsi->FSIOper().get() )->enableStressComputation (1);
292 
293  bool valveIsOpen = true;
294 
295  vectorPtr_Type solution ( new vector_Type ( (*M_fsi->FSIOper()->couplingVariableMap() ) ) );
296 
297  M_fsi->FSIOper()->extrapolation ( *solution );
298 
299  for ( ; M_data->dataFluid()->dataTime()->canAdvance(); M_data->dataFluid()->dataTime()->updateTime(), M_data->dataSolid()->dataTime()->updateTime(), ++iter)
300  {
301  //Return value for the testsuite
302  M_returnValue = EXIT_FAILURE;
303 
304  LifeV::Real flux = M_fsi->FSIOper()->fluid().flux (2, M_fsi->displacement() );
305  if ( valveIsOpen)
306  {
307  if ( iter == 3 /*flux < -100*/)
308  {
309  valveIsOpen = false;
310  M_fsi->setFluidBC (BCh_monolithicFluid (*M_fsi->FSIOper(), valveIsOpen) );
311  //M_fsi->FSIOper()->BCh_fluid()->substituteBC( (const LifeV::bcFlag_Type) 2, bcf, LifeV::Essential, LifeV::Full, (const LifeV::UInt) 3);
312  }
313  }
314  // close the valve
315  else
316  {
317  if (false && M_fsi->FSIOper()->fluid().pressure (2, M_fsi->displacement() ) < LifeV::LumpedHeart::M_pressure )
318  {
319  valveIsOpen = true;
320  M_fsi->setFluidBC (BCh_monolithicFluid (*M_fsi->FSIOper(), valveIsOpen) );
321  //M_fsi->FSIOper()->BCh_fluid()->substituteBC( (const LifeV::bcFlag_Type) 2, bcf, LifeV::Natural, LifeV::Full, 3);
322  }
323  }
324 
325  int flag = 2;
326  FC0.renewParameters ( *M_fsi, 3 );
327  LH.renewParameters ( *M_fsi->FSIOper(), flag, M_data->dataFluid()->dataTime()->time(), flux );
328 
329  boost::timer _timer;
330 
331  if (iter % M_saveEvery == 0)
332  {
333  M_fsi->FSIOper()->exportSolidDisplacement (*M_solidDisp);
334 
335  M_fsi->FSIOper()->exportFluidVelocityAndPressure (*M_velAndPressure);
336  M_exporterSolid->postProcess ( M_data->dataFluid()->dataTime()->time() );
337 
338  *M_fluidDisp = M_fsi->FSIOper()->meshDisp();
339  M_exporterFluid->postProcess ( M_data->dataFluid()->dataTime()->time() );
340  }
341 
342  // This is just the previous solution. Should use the extrapolation from time advance
343  M_fsi->FSIOper()->extrapolation ( *solution );
344 
345  M_fsi->iterate ( solution );
346 
347  // shift_right of the solution of all the time advance classes in the FSIOperator
348  M_fsi->FSIOper()->updateSolution ( *solution );
349 
350  M_fsi->FSIOper()->displayer().leaderPrintMax ("[fsi_run] Iteration ", iter);
351  M_fsi->FSIOper()->displayer().leaderPrintMax (" was done in : ", _timer.elapsed() );
352 
353  std::cout << "solution norm " << iter << " : "
354  << M_fsi->displacement().norm2() << "\n";
355 
356  // ///////// CHECKING THE RESULTS OF THE TEST AT EVERY TIMESTEP
357  if (!M_data->method().compare ("monolithicGI") )
358  {
359  checkCEResult (M_data->dataFluid()->dataTime()->time() );
360  }
361  else
362  {
363  checkGCEResult (M_data->dataFluid()->dataTime()->time() );
364  }
365 
366  }
367 
368  std::cout << "Total computation time = "
369  << _overall_timer.elapsed() << "s" << "\n";
370 
371  return M_returnValue;
372 
373  }
374 
375 private:
376 
377  void checkCEResult (const LifeV::Real& time);
378  void checkGCEResult (const LifeV::Real& time);
379 
381  dataPtr_Type M_data;
382 
385  filterPtr_Type M_importerSolid;
386  filterPtr_Type M_importerFluid;
387  vectorPtr_Type M_velAndPressure;
388  vectorPtr_Type M_fluidDisp;
389  vectorPtr_Type M_solidDisp;
390 
391  std::vector<vectorPtr_Type> M_solidStencil;
392  std::vector<vectorPtr_Type> M_fluidStencil;
393  std::vector<vectorPtr_Type> M_ALEStencil;
394 
397 
399  // vectorPtr_Type M_WS;
400  LifeV::UInt M_saveEvery;
402 
403 public:
404 
405  void resultCorrect (LifeV::Real time)
406  {
407  std::cout << "Result correct at time: " << time << std::endl;
408  M_returnValue = EXIT_SUCCESS;
409  }
410 };
411 
412 
413 struct FSIChecker
414 {
415  FSIChecker ( GetPot const& _data_file ) :
417  {}
418 
419  int operator() ()
420  {
421  std::shared_ptr<Problem> fsip;
422 
423  try
424  {
425  fsip = std::shared_ptr<Problem> ( new Problem ( data_file ) );
426  return fsip->run();
427  }
428  catch ( std::exception const& _ex )
429  {
430  std::cout << "caught exception : " << _ex.what() << "\n";
431  }
432  return EXIT_FAILURE;
433 
434  }
435 
436  GetPot data_file;
437  LifeV::Vector disp;
438 };
439 
440 
441 namespace LifeV
442 {
443 
444 namespace
445 {
446 static bool regIF = (PRECFactory::instance().registerProduct ( "Ifpack", &createIfpack ) );
447 static bool regML = (PRECFactory::instance().registerProduct ( "ML", &createML ) );
448 }
449 }
450 
451 
452 int main (int argc, char** argv)
453 {
454 #ifdef HAVE_MPI
455  MPI_Init (&argc, &argv);
456 #else
457  std::cout << "% using serial Version" << std::endl;
458 #endif
459 
460  GetPot command_line (argc, argv);
461 
462  const std::string data_file_name = command_line.follow ("data", 2, "-f", "--file");
463  GetPot data_file (data_file_name);
464  FSIChecker _sp_check ( data_file );
465  int returnValue = _sp_check();
466 
467 #ifdef HAVE_MPI
468  MPI_Finalize();
469 #endif
470 
471  return returnValue;
472 
473 }
474 
475 void Problem::checkCEResult (const LifeV::Real& time)
476 {
477  LifeV::Real dispNorm = M_fsi->displacement().norm2();
478  if (time == 0.000 && (dispNorm - 106344) / dispNorm * (dispNorm - 106344) / dispNorm < 1e-3)
479  {
480  Problem::resultCorrect (time);
481  }
482  else if (time == 0.001 && (dispNorm - 147532) / dispNorm * (dispNorm - 147532) / dispNorm < 1e-3)
483  {
484  Problem::resultCorrect (time);
485  }
486  else if (time == 0.002 && (dispNorm - 108216) / dispNorm * (dispNorm - 108216) / dispNorm < 1e-3)
487  {
488  Problem::resultCorrect (time);
489  }
490  else if (time == 0.003 && (dispNorm - 105437) / dispNorm * (dispNorm - 105437) / dispNorm < 1e-3)
491  {
492  Problem::resultCorrect (time);
493  }
494  else if (time == 0.004 && (dispNorm - 104585) / dispNorm * (dispNorm - 104585) / dispNorm < 1e-3)
495  {
496  Problem::resultCorrect (time);
497  }
498 
499 }
500 
501 
502 void Problem::checkGCEResult (const LifeV::Real& time)
503 {
504  LifeV::Real dispNorm = M_fsi->displacement().norm2();
505  if (time == 0.000 && (dispNorm - 110316) / dispNorm * (dispNorm - 110316) / dispNorm < 1e-5)
506  {
507  Problem::resultCorrect (time);
508  }
509  else if (time == 0.001 && (dispNorm - 99468.8) / dispNorm * (dispNorm - 99468.8) / dispNorm < 1e-5)
510  {
511  Problem::resultCorrect (time);
512  }
513  else if (time == 0.002 && (dispNorm - 91003.1) / dispNorm * (dispNorm - 91003.1) / dispNorm < 1e-5)
514  {
515  Problem::resultCorrect (time);
516  }
517  else if (time == 0.003 && (dispNorm - 90179.9) / dispNorm * (dispNorm - 90179.9) / dispNorm < 1e-5)
518  {
519  Problem::resultCorrect (time);
520  }
521  else if (time == 0.004 && (dispNorm - 88319.3) / dispNorm * (dispNorm - 88319.3) / dispNorm < 1e-5)
522  {
523  Problem::resultCorrect (time);
524  }
525 }
void checkCEResult(const LifeV::Real &time)
void assignFunction(bcBase_Type &base)
Assign the function to the base of the BCHandler.
LifeV::FactorySingleton< LifeV::Factory< LifeV::FSIOperator, std::string > > FSIFactory_Type
int main(int argc, char **argv)
GetPot(const int argc_, char **argv_, const char *FieldSeparator=0x0)
Definition: GetPot.hpp:507
#define debugStream
Definition: LifeDebug.hpp:182
std::shared_ptr< FSISolver > fsi_solver_ptr
void resultCorrect(LifeV::Real time)
FSIChecker(GetPot const &_data_file)
NdebugStream noDebugStream(int=0, NdebugStream::stprintf=&printf)
Definition: LifeDebug.hpp:183
Problem(GetPot const &data_file)
std::shared_ptr< ensightFilter_Type > ensightFilterPtr_Type
LifeV::ExporterEnsight< LifeV::FSIOperator::mesh_Type > ensightFilter_Type
void checkGCEResult(const LifeV::Real &time)