LifeV
lifev/electrophysiology/examples/example_bidomain/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 Test for ElectroETAbidomainSolver and IonicMinimalModel
30 
31  This example make use of a bidomain solver which should not
32  be considered as a solver! If you would like to implement
33  a bidomain solver, please make write it from scratch.
34 
35  @date 08 - 013
36  @author Toni Lassila <toni.lassila@epfl.ch>
37 
38  @contributor
39  @mantainer Toni Lassila <toni.lassila@epfl.ch>
40  */
41 
42 // Tell the compiler to ignore specific kind of warnings:
43 #pragma GCC diagnostic ignored "-Wunused-variable"
44 #pragma GCC diagnostic ignored "-Wunused-parameter"
45 
46 #include <Epetra_ConfigDefs.h>
47 #ifdef EPETRA_MPI
48 #include <mpi.h>
49 #include <Epetra_MpiComm.h>
50 #else
51 #include <Epetra_SerialComm.h>
52 #endif
53 
54 //Tell the compiler to restore the warning previously silented
55 #pragma GCC diagnostic warning "-Wunused-variable"
56 #pragma GCC diagnostic warning "-Wunused-parameter"
57 
58 #include <fstream>
59 #include <string>
60 
61 #include <lifev/core/array/VectorSmall.hpp>
62 
63 #include <lifev/core/array/VectorEpetra.hpp>
64 #include <lifev/core/array/MatrixEpetra.hpp>
65 #include <lifev/core/array/MapEpetra.hpp>
66 #include <lifev/core/mesh/MeshData.hpp>
67 #include <lifev/core/mesh/MeshPartitioner.hpp>
68 #include <lifev/core/filter/ExporterEnsight.hpp>
69 #include <lifev/core/filter/ExporterHDF5.hpp>
70 #include <lifev/core/filter/ExporterEmpty.hpp>
71 
72 #include <lifev/core/algorithm/LinearSolver.hpp>
73 #include <lifev/electrophysiology/examples/example_bidomain/ElectroETABidomainSolver.hpp>
74 
75 #include <lifev/core/filter/ExporterEnsight.hpp>
76 #ifdef HAVE_HDF5
77 #include <lifev/core/filter/ExporterHDF5.hpp>
78 #endif
79 #include <lifev/core/filter/ExporterEmpty.hpp>
80 
81 #include <lifev/electrophysiology/solver/IonicModels/IonicMinimalModel.hpp>
82 #include <lifev/core/fem/BCManage.hpp>
83 #include <lifev/core/LifeV.hpp>
84 
85 #include <Teuchos_RCP.hpp>
86 #include <Teuchos_ParameterList.hpp>
87 #include "Teuchos_XMLParameterListHelpers.hpp"
88 
89 
90 using namespace LifeV;
91 
92 Real smoothing (const Real& /*t*/, const Real& x, const Real& y, const Real& z, const ID& /*i*/)
93 {
94 
95  Real pacingSite_X = 0.0;
96  Real pacingSite_Y = 0.0;
97  Real pacingSite_Z = 0.0;
98  Real stimulusRadius = 0.15;
99 
100  if ( std::abs ( x - pacingSite_X ) <= stimulusRadius && std::abs ( z - pacingSite_Z ) <= stimulusRadius && std::abs ( y - pacingSite_Y ) <= stimulusRadius)
101  {
102  return 1.0;
103  }
104  else
105  {
106  return 0.0;
107  }
108 }
109 
110 Real PacingProtocol ( const Real& /*t*/, const Real& x, const Real& y, const Real& z, const ID& /*id*/)
111 {
112 
113  Real pacingSite_X = 0.0;
114  Real pacingSite_Y = 0.0;
115  Real pacingSite_Z = 0.0;
116  Real stimulusRadius = 0.15;
117  Real stimulusValue = 10.0;
118 
119  Real returnValue1;
120 
121  if ( std::abs ( x - pacingSite_X ) <= stimulusRadius && std::abs ( z - pacingSite_Z ) <= stimulusRadius && std::abs ( y - pacingSite_Y ) <= stimulusRadius)
122  {
123  returnValue1 = stimulusValue;
124  }
125  else
126  {
127  returnValue1 = 0.;
128  }
129 
130  return returnValue1;
131 }
132 
133 static Real bcDirichletZero (const Real&, const Real&, const Real&, const Real&, const LifeV::ID&)
134 {
135  return 0.000;
136 }
137 
138 static Real bcDirichletOne (const Real&, const Real&, const Real&, const Real&, const LifeV::ID&)
139 {
140  return 1;
141 }
142 
143 
144 Int main ( Int argc, char** argv )
145 {
146 
147  //! Initializing Epetra communicator
148  MPI_Init (&argc, &argv);
149  std::shared_ptr<Epetra_Comm> Comm ( new Epetra_MpiComm (MPI_COMM_WORLD) );
150  if ( Comm->MyPID() == 0 )
151  {
152  std::cout << "% using MPI" << std::endl;
153  }
154 
155  //********************************************//
156  // Starts the chronometer. //
157  //********************************************//
158  // LifeChrono chronoinitialsettings;
159  // chronoinitialsettings.start();
160 
161  typedef RegionMesh<LinearTetra> mesh_Type;
162  typedef std::function < Real (const Real& /*t*/,
163  const Real & x,
164  const Real & y,
165  const Real& /*z*/,
166  const ID& /*i*/ ) > function_Type;
167 
168  typedef ElectroETABidomainSolver< mesh_Type, IonicMinimalModel > bidomainSolver_Type;
169  typedef std::shared_ptr< bidomainSolver_Type > bidomainSolverPtr_Type;
170  typedef VectorEpetra vector_Type;
171  typedef std::shared_ptr<vector_Type> vectorPtr_Type;
172 
173  LifeChrono chronoinitialsettings;
174 
175  if ( Comm->MyPID() == 0 )
176  {
177  chronoinitialsettings.start();
178  }
179 
180  //********************************************//
181  // Import parameters from an xml list. Use //
182  // Teuchos to create a list from a given file //
183  // in the execution directory. //
184  //********************************************//
185 
186  if ( Comm->MyPID() == 0 )
187  {
188  std::cout << "Importing parameters list...";
189  }
190  Teuchos::ParameterList bidomainList = * ( Teuchos::getParametersFromXmlFile ( "BidomainSolverParamList.xml" ) );
191  if ( Comm->MyPID() == 0 )
192  {
193  std::cout << " Done!" << std::endl;
194  }
195 
196  //********************************************//
197  // Creates a new model object representing the//
198  // model from Aliev and Panfilov 1996. The //
199  // model input are the parameters. Pass the //
200  // parameter list in the constructor //
201  //********************************************//
202  if ( Comm->MyPID() == 0 )
203  {
204  std::cout << "Building Constructor for Minimal Model with parameters ... ";
205  }
206  std::shared_ptr<IonicMinimalModel> model ( new IonicMinimalModel() );
207  if ( Comm->MyPID() == 0 )
208  {
209  std::cout << " Done!" << std::endl;
210  }
211 
212 
213  //********************************************//
214  // In the parameter list we need to specify //
215  // the mesh name and the mesh path. //
216  //********************************************//
217  std::string meshName = bidomainList.get ("mesh_name", "lid16.mesh");
218  std::string meshPath = bidomainList.get ("mesh_path", "./");
219 
220  //********************************************//
221  // We need the GetPot datafile for to setup //
222  // the preconditioner. //
223  //********************************************//
224  GetPot dataFile (argc, argv);
225 
226  //********************************************//
227  // We create three solvers to solve with: //
228  // 1) Operator Splitting method //
229  // 2) Ionic Current Interpolation //
230  // 3) State Variable Interpolation //
231  //********************************************//
232  if ( Comm->MyPID() == 0 )
233  {
234  std::cout << "Building bidomain Solvers... ";
235  }
236 
237  bidomainSolverPtr_Type splitting ( new bidomainSolver_Type ( meshName, meshPath, dataFile, model ) );
238  if ( Comm->MyPID() == 0 )
239  {
240  std::cout << " Splitting solver done... ";
241  }
242 
243 
244  //********************************************//
245  // Setting up the initial condition form //
246  // a given function. //
247  //********************************************//
248  if ( Comm->MyPID() == 0 )
249  {
250  std::cout << "\nInitializing potential: " ;
251  }
252 
253  // Initial pacing
254  function_Type pacing = &PacingProtocol;
255  splitting -> initializePotential();
256 
257  //HeartUtility::setValueOnBoundary( *(splitting -> potentialTransPtr() ), splitting -> fullMeshPtr(), 1.0, 6 );
258 
259  //function_Type f = &smoothing;
260  //vectorPtr_Type smoother( new vector_Type( splitting -> potentialTransPtr() -> map() ) );
261  //splitting -> feSpacePtr() -> interpolate ( static_cast< FESpace< RegionMesh<LinearTetra>, MapEpetra >::function_Type > ( f ), *smoother , 0);
262  //(*smoother) *= *(splitting -> potentialTransPtr() );
263  //splitting -> setPotentialTransPtr(smoother);
264 
265  //setting up initial conditions
266  * ( splitting -> globalSolution().at (1) ) = 1.0;
267  * ( splitting -> globalSolution().at (2) ) = 1.0;
268  * ( splitting -> globalSolution().at (3) ) = 0.021553043080281;
269 
270  if ( Comm->MyPID() == 0 )
271  {
272  std::cout << "Done! \n" ;
273  }
274 
275  //********************************************//
276  // Setting up the time data //
277  //********************************************//
278  splitting -> setParameters ( bidomainList );
279 
280  //********************************************//
281  // Settung up the Boundary condition //
282  //********************************************//
283 
284  if ( Comm->MyPID() == 0 )
285  {
286  std::cout << "-- Reading bc ..";
287  }
288 
289  std::shared_ptr<LifeV::BCHandler> bcs (new LifeV::BCHandler() );
290 
291  LifeV::BCFunctionBase zero (bcDirichletZero);
292 
293  std::vector<LifeV::ID> compx (1, 0), compy (1, 1), compz (1, 2);
294  bcs->addBC ("boundaryDirichletZero", 600, LifeV::Essential, LifeV::Full, zero, 3);
295 
296  //bcs->addBC("boundaryNeumannBase", 99, LifeV::Natural, LifeV::Full, one,1);
297  //partition mesh
298  bcs->bcUpdate ( *splitting->localMeshPtr(), splitting->feSpacePtr()->feBd(), splitting->feSpacePtr()->dof() );
299 
300  if ( Comm->MyPID() == 0 )
301  {
302  std::cout << " Done!" << std::endl;
303  }
304 
305 
306  //********************************************//
307  // Create a fiber direction //
308  //********************************************//
309  if ( Comm->MyPID() == 0 )
310  {
311  std::cout << "\nImporting fibers: " ;
312  }
313 
314  std::shared_ptr<FESpace< mesh_Type, MapEpetra > > Space3D
315  ( new FESpace< mesh_Type, MapEpetra > ( splitting -> localMeshPtr(), "P1", 3, splitting -> commPtr() ) );
316 
317  std::shared_ptr<VectorEpetra> fiber ( new VectorEpetra ( Space3D -> map() ) );
318  std::string nm = bidomainList.get ("fiber_file", "FiberDirection") ;
319  ElectrophysiologyUtility::setupFibers ( *fiber, 0.0, 0.0, 1.0 );
320  splitting -> setFiberPtr (fiber);
321 
322  if ( Comm->MyPID() == 0 )
323  {
324  std::cout << "Done! \n" ;
325  }
326  //********************************************//
327  // Create the global matrix: mass + stiffness //
328  //********************************************//
329  if ( Comm->MyPID() == 0 )
330  {
331  std::cout << "\nSetup operators: " ;
332  }
333 
334  //splitting -> setupLumpedMassMatrix();
335  splitting -> setupMassMatrix();
336  splitting -> setupStiffnessMatrix();
337  splitting -> setupGlobalMatrix();
338  if ( Comm->MyPID() == 0 )
339  {
340  std::cout << "Done! \n" ;
341  }
342 
343  //********************************************//
344  // Creating exporters to save the solution //
345  //********************************************//
346  ExporterHDF5< RegionMesh <LinearTetra> > exporterSplitting;
347 
348  splitting -> setupExporter ( exporterSplitting, bidomainList.get ("OutputFile", "Splitting") );
349 
350  splitting -> exportSolution ( exporterSplitting, 0);
351 
352  //********************************************//
353  // Solving the system //
354  //********************************************//
355  if ( Comm->MyPID() == 0 )
356  {
357  std::cout << "\nstart solving: " ;
358  }
359 
360  bidomainSolver_Type::vectorPtr_Type dtVec ( new VectorEpetra ( splitting->feSpacePtr() -> map(), LifeV::Unique ) );
361  ExporterHDF5<mesh_Type> Exp;
362  Exp.setMeshProcId ( splitting -> localMeshPtr(), splitting -> commPtr() -> MyPID() );
363  Exp.setPrefix (bidomainList.get ("OutputTimeSteps", "TimeSteps") );
364  Exp.addVariable ( ExporterData<mesh_Type>::ScalarField, "dt", splitting->feSpacePtr(), dtVec, UInt (0) );
365 
366  Real dt = bidomainList.get ("timeStep", 0.1);
367  Real TF = bidomainList.get ("endTime", 150.0);
368  Int iter = bidomainList.get ("saveStep", 1.0) / dt;
369  Int meth = bidomainList.get ("meth", 1 );
370  Real dt_min = dt / 50.0;
371  Int k (0), j (0);
372  Int nodes;
373 
374  Real timeReac = 0.0;
375  Real timeDiff = 0.0;
376  LifeChrono chrono;
377 
378  Real stimulusStart = 0.0;
379  Real stimulusStop = 2.0;
380 
381  for ( Real t = 0.0; t < TF; )
382  {
383 
384  if ( (t >= stimulusStart ) && (t <= stimulusStop + dt) )
385  {
386  splitting -> setAppliedCurrentFromFunctionIntra ( pacing );
387  // splitting->appliedCurrentIntraPtr()->showMe();
388  }
389  else
390  {
391  splitting -> initializeAppliedCurrentIntra();
392  }
393 
394  chrono.reset();
395  if (meth == 1)
396  {
397  chrono.start();
398  // splitting->solveOneReactionStepROS3P(dtVec, dt_min);
399  chrono.stop();
400  }
401  else
402  {
403  chrono.start();
404  splitting->solveOneReactionStepFE( );
405  chrono.stop();
406  }
407 
408  timeReac += chrono.globalDiff ( *Comm );
409 
410  (*splitting->rhsPtrUnique() ) *= 0.0;
411  splitting->updateRhs();
412 
413  chrono.reset();
414  //bcManage ( *splitting->stiffnessMatrixPtr() , *splitting->rhsPtrUnique(), *splitting->localMeshPtr(), splitting->feSpacePtr()->dof(), *bcs, splitting->feSpacePtr()->feBd(), 1.0, t );
415  //splitting->rhsPtrUnique()->spy("rhs.dat");
416  //splitting->stiffnessMatrixPtr()->spy("Stiffness");
417  chrono.start();
418  splitting->solveOneDiffusionStepBE();
419  chrono.stop();
420  timeDiff += chrono.globalDiff ( *Comm );
421 
422  if ( k % iter == 0 )
423  {
424  splitting -> exportSolution (exporterSplitting, t);
425  Exp.postProcess (t);
426  }
427 
428  nodes = dtVec->epetraVector().MyLength();
429  j = dtVec->blockMap().GID (0);
430  dt_min = (*dtVec) [j];
431  for (int i = 1; i < nodes; i++)
432  {
433  j = dtVec->blockMap().GID (i);
434  if (dt_min > (*dtVec) [j])
435  {
436  dt_min = (*dtVec) [j];
437  }
438  }
439 
440  k++;
441 
442  t = t + dt;
443 
444  if ( Comm->MyPID() == 0 )
445  {
446  std::cout << "\n\n\nActual time : " << t << std::endl << std::endl << std::endl;
447  }
448 
449  }
450 
451  Real normSolution = ( ( splitting -> globalSolution().at (0) )->norm2() );
452  if ( Comm->MyPID() == 0 )
453  {
454  std::cout << "2-norm of potential solution: " << normSolution << std::endl;
455  }
456 
457  exporterSplitting.closeFile();
458  Exp.closeFile();
459 
460 
461  //********************************************//
462  // Saving Fiber direction to file //
463  //********************************************//
464  splitting -> exportFiberDirection();
465 
466 
467  if ( Comm->MyPID() == 0 )
468  {
469  chronoinitialsettings.stop();
470  std::cout << "\n\n\nTotal lapsed time : " << chronoinitialsettings.diff() << std::endl;
471  std::cout << "Diffusion time : " << timeDiff << std::endl;
472  std::cout << "Reaction time : " << timeReac << std::endl;
473  std::cout << "\nThank you for using ETA_bidomainSolver.\nI hope to meet you again soon!\n All the best for your simulation :P\n " ;
474  }
475  MPI_Barrier (MPI_COMM_WORLD);
476  MPI_Finalize();
477 
478  Real returnValue;
479 
480  if (std::abs (normSolution - 14.182) > 1e-4 )
481  {
482  returnValue = EXIT_FAILURE; // Norm of solution did not match
483  }
484  else
485  {
486  returnValue = EXIT_SUCCESS;
487  }
488  return ( returnValue );
489 }
VectorEpetra - The Epetra Vector format Wrapper.
void assignFunction(bcBase_Type &base)
Assign the function to the base of the BCHandler.
int main(int argc, char **argv)
GetPot(const int argc_, char **argv_, const char *FieldSeparator=0x0)
Definition: GetPot.hpp:507
static Real bcDirichletOne(const Real &, const Real &, const Real &, const Real &, const LifeV::ID &)
IonicModel - This class implements an ionic model.
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
static Real bcDirichletZero(const Real &, const Real &, const Real &, const Real &, const LifeV::ID &)
uint32_type ID
IDs.
Definition: LifeV.hpp:194
double Real
Generic real data.
Definition: LifeV.hpp:175
Real smoothing(const Real &, const Real &x, const Real &y, const Real &z, const ID &)
Real PacingProtocol(const Real &, const Real &x, const Real &y, const Real &z, const ID &)