LifeV
lifev/electrophysiology/examples/example_benchmarkPurkinje/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 Electrophysiology benchmark with Noble-Purkinje excitation model
30 
31  @date 01−2013
32  @author Simone Rossi <simone.rossi@epfl.ch>
33  @author Simone Palamara <palamara.simone@gmail.com>
34 
35  @contributor
36  @mantainer Simone Rossi <simone.rossi@epfl.ch>
37  */
38 
39 // Tell the compiler to ignore specific kind of warnings:
40 #pragma GCC diagnostic ignored "-Wunused-variable"
41 #pragma GCC diagnostic ignored "-Wunused-parameter"
42 
43 #include <Epetra_ConfigDefs.h>
44 #ifdef EPETRA_MPI
45 #include <mpi.h>
46 #include <Epetra_MpiComm.h>
47 #else
48 #include <Epetra_SerialComm.h>
49 #endif
50 
51 //Tell the compiler to restore the warning previously silented
52 #pragma GCC diagnostic warning "-Wunused-variable"
53 #pragma GCC diagnostic warning "-Wunused-parameter"
54 
55 
56 
57 #include <fstream>
58 #include <string>
59 
60 #include <lifev/core/array/VectorSmall.hpp>
61 
62 #include <lifev/core/array/VectorEpetra.hpp>
63 #include <lifev/core/array/MatrixEpetra.hpp>
64 #include <lifev/core/array/MapEpetra.hpp>
65 #include <lifev/core/mesh/MeshData.hpp>
66 #include <lifev/core/mesh/MeshPartitioner.hpp>
67 #include <lifev/core/filter/ExporterEnsight.hpp>
68 #include <lifev/core/filter/ExporterHDF5.hpp>
69 #include <lifev/core/filter/ExporterEmpty.hpp>
70 
71 #include <lifev/core/algorithm/LinearSolver.hpp>
72 #include <lifev/electrophysiology/solver/ElectroETAMonodomainSolver.hpp>
73 
74 #include <lifev/core/filter/ExporterEnsight.hpp>
75 #ifdef HAVE_HDF5
76 #include <lifev/core/filter/ExporterHDF5.hpp>
77 #endif
78 #include <lifev/core/filter/ExporterEmpty.hpp>
79 
80 #include <lifev/electrophysiology/solver/IonicModels/IonicMinimalModel.hpp>
81 #include <lifev/electrophysiology/solver/IonicModels/IonicLuoRudyI.hpp>
82 #include <lifev/electrophysiology/solver/IonicModels/IonicTenTusscher06.hpp>
83 #include <lifev/electrophysiology/solver/IonicModels/IonicHodgkinHuxley.hpp>
84 #include <lifev/electrophysiology/solver/IonicModels/IonicNoblePurkinje.hpp>
85 #include <lifev/electrophysiology/util/ElectrophysiologyUtility.hpp>
86 #include <lifev/core/LifeV.hpp>
87 
88 #include <Teuchos_RCP.hpp>
89 #include <Teuchos_ParameterList.hpp>
90 #include "Teuchos_XMLParameterListHelpers.hpp"
91 
92 #include <sys/stat.h>
93 
94 using namespace LifeV;
95 
96 Real PacingProtocolMM ( const Real& t, const Real& x, const Real& y, const Real& z, const ID& /*id*/)
97 {
98 
99  Real pacingSite_X = 0.0;
100  Real pacingSite_Y = 0.0;
101  Real pacingSite_Z = 0.0;
102  Real stimulusRadius = 0.15;
103  Real stimulusValue = 10;
104 
105  Real returnValue;
106 
107  if ( std::abs ( x - pacingSite_X ) <= stimulusRadius
108  &&
109  std::abs ( z - pacingSite_Z ) <= stimulusRadius
110  &&
111  std::abs ( y - pacingSite_Y ) <= stimulusRadius
112  &&
113  t <= 2)
114  {
115  returnValue = stimulusValue;
116  }
117  else
118  {
119  returnValue = 0.;
120  }
121 
122  return returnValue;
123 }
124 
125 Real PacingProtocolHH ( const Real& t, const Real& x, const Real& y, const Real& z, const ID& /*id*/)
126 {
127 
128  Real pacingSite_X = 0.0;
129  Real pacingSite_Y = 0.0;
130  Real pacingSite_Z = 0.0;
131  Real stimulusRadius = 0.15;
132  Real stimulusValue = 500.;
133 
134  Real returnValue;
135 
136  if ( std::abs ( x - pacingSite_X ) <= stimulusRadius
137  &&
138  std::abs ( z - pacingSite_Z ) <= stimulusRadius
139  &&
140  std::abs ( y - pacingSite_Y ) <= stimulusRadius
141  &&
142  t <= 2)
143  {
144  returnValue = stimulusValue;
145  }
146  else
147  {
148  returnValue = 0.;
149  }
150 
151  return returnValue;
152 }
153 
154 Real PacingProtocol ( const Real& t, const Real& x, const Real& y, const Real& z, const ID& /*id*/)
155 {
156 
157  Real pacingSite_X = 0.0;
158  Real pacingSite_Y = 0.0;
159  Real pacingSite_Z = 0.0;
160  Real stimulusRadius = 0.15;
161  Real stimulusValue = 50;
162 
163  Real returnValue;
164 
165  if ( std::abs ( x - pacingSite_X ) <= stimulusRadius
166  &&
167  std::abs ( z - pacingSite_Z ) <= stimulusRadius
168  &&
169  std::abs ( y - pacingSite_Y ) <= stimulusRadius
170  &&
171  t <= 2)
172  {
173  returnValue = stimulusValue;
174  }
175  else
176  {
177  returnValue = 0.;
178  }
179 
180  return returnValue;
181 }
182 
183 
184 Int main ( Int argc, char** argv )
185 {
186 
187  //! Initializing Epetra communicator
188  MPI_Init (&argc, &argv);
189  std::shared_ptr<Epetra_Comm> Comm ( new Epetra_MpiComm (MPI_COMM_WORLD) );
190  if ( Comm->MyPID() == 0 )
191  {
192  std::cout << "% using MPI" << std::endl;
193  }
194 
195  //*********************************************//
196  // creating output folder
197  //*********************************************//
198  GetPot commandLine ( argc, argv );
199  std::string problemFolder = commandLine.follow ( "Output", 2, "-o", "--output" );
200  // Create the problem folder
201  if ( problemFolder.compare ("./") )
202  {
203  problemFolder += "/";
204 
205  if ( Comm->MyPID() == 0 )
206  {
207  mkdir ( problemFolder.c_str(), 0777 );
208  }
209  }
210 
211  //********************************************//
212  // Starts the chronometer. //
213  //********************************************//
214 
215  typedef RegionMesh<LinearTetra> mesh_Type;
216  typedef std::function < Real (const Real& /*t*/,
217  const Real & x,
218  const Real & y,
219  const Real& /*z*/,
220  const ID& /*i*/ ) > function_Type;
221 
222  typedef ElectroIonicModel ionicModel_Type;
223  typedef std::shared_ptr<ionicModel_Type> ionicModelPtr_Type;
224  typedef ElectroETAMonodomainSolver< mesh_Type, ionicModel_Type > monodomainSolver_Type;
225  typedef std::shared_ptr< monodomainSolver_Type > monodomainSolverPtr_Type;
226 
227  typedef VectorEpetra vector_Type;
228  typedef std::shared_ptr<vector_Type> vectorPtr_Type;
229 
230 
231  LifeChrono chronoinitialsettings;
232 
233  if ( Comm->MyPID() == 0 )
234  {
235  chronoinitialsettings.start();
236  }
237 
238  //********************************************//
239  // Import parameters from an xml list. Use //
240  // Teuchos to create a list from a given file //
241  // in the execution directory. //
242  //********************************************//
243 
244  if ( Comm->MyPID() == 0 )
245  {
246  std::cout << "Importing parameters list...";
247  }
248  Teuchos::ParameterList monodomainList = * ( Teuchos::getParametersFromXmlFile ( "MonodomainSolverParamList.xml" ) );
249  if ( Comm->MyPID() == 0 )
250  {
251  std::cout << " Done!" << std::endl;
252  }
253 
254  std::string ionic_model ( monodomainList.get ("ionic_model", "minimalModel") );
255  if ( Comm->MyPID() == 0 )
256  {
257  std::cout << "\nIonic_Model:" << ionic_model;
258  }
259 
260 
261 
262  //********************************************//
263  // Creates a new model object representing the//
264  // model from Aliev and Panfilov 1996. The //
265  // model input are the parameters. Pass the //
266  // parameter list in the constructor //
267  //********************************************//
268  if ( Comm->MyPID() == 0 )
269  {
270  std::cout << "\nBuilding Constructor for " << ionic_model << " Model with parameters ... ";
271  }
272  ionicModelPtr_Type model;
273  std::shared_ptr<IonicNoblePurkinje> excitationModel (new IonicNoblePurkinje() );
274 
275  if ( ionic_model == "LuoRudyI" )
276  {
277  model.reset ( new IonicLuoRudyI() );
278  }
279  if ( ionic_model == "TenTusscher06")
280  {
281  model.reset (new IonicTenTusscher06() );
282  }
283  if ( ionic_model == "HodgkinHuxley")
284  {
285  model.reset (new IonicHodgkinHuxley() );
286  }
287  if ( ionic_model == "NoblePurkinje")
288  {
289  model.reset (new IonicNoblePurkinje() );
290  }
291  if ( ionic_model == "MinimalModel")
292  {
293  model.reset ( new IonicMinimalModel() );
294  }
295 
296  if ( Comm->MyPID() == 0 )
297  {
298  std::cout << " Done!" << std::endl;
299  }
300 
301  model -> showMe();
302 
303 
304  //********************************************//
305  // In the parameter list we need to specify //
306  // the mesh name and the mesh path. //
307  //********************************************//
308  std::string meshName = monodomainList.get ("mesh_name", "lid16.mesh");
309  std::string meshPath = monodomainList.get ("mesh_path", "./");
310 
311  //********************************************//
312  // We need the GetPot datafile for to setup //
313  // the preconditioner. //
314  //********************************************//
315  GetPot command_line (argc, argv);
316  const std::string data_file_name = command_line.follow ("data", 2, "-f", "--file");
317  GetPot dataFile (data_file_name);
318 
319  //********************************************//
320  // We create three solvers to solve with: //
321  // 1) Operator Splitting method //
322  // 2) Ionic Current Interpolation //
323  // 3) State Variable Interpolation //
324  //********************************************//
325  if ( Comm->MyPID() == 0 )
326  {
327  std::cout << "Building Monodomain Solvers... ";
328  }
329 
330  monodomainSolverPtr_Type solver ( new monodomainSolver_Type ( meshName, meshPath, dataFile, model ) );
331  if ( Comm->MyPID() == 0 )
332  {
333  std::cout << " solver done... ";
334  }
335 
336 
337 
338 
339  //********************************************//
340  // Setting up the initial condition form //
341  // a given function. //
342  //********************************************//
343  if ( Comm->MyPID() == 0 )
344  {
345  std::cout << "\nInitializing potential and gating variables: " ;
346  }
347 
348  // Initial pacing
349  solver -> initializePotential();
350  solver -> initializeAppliedCurrent();
351  solver -> setInitialConditions();
352 
353  if ( Comm->MyPID() == 0 )
354  {
355  std::cout << "\nDone. " << std::flush ;
356  }
357 
358  //********************************************//
359  // MESH STUFF //
360  //********************************************//
361 
362  std::vector<Real> junction (3, 0.0);
363  //Real Radius = 0.1;
364  UInt numberOfSources (4);
365  UInt numberLocalSources (numberOfSources / Comm->NumProc() );
366  if ( Comm->MyPID() == 0 )
367  {
368  numberLocalSources += numberOfSources % Comm->NumProc();
369  }
370  UInt flag (300);
371  std::vector<ID> containerPointsGivenFlag, containerPointsWithAppliedCurrent;
372  std::vector<Real> activationTime;
373  double deltaT (2.0);
374  ElectrophysiologyUtility::allIdsPointsWithGivenFlag<mesh_Type> (containerPointsGivenFlag, flag, solver -> appliedCurrentPtr(), solver -> fullMeshPtr() );
375  ElectrophysiologyUtility::randomNPointsInSetAndNeighborhood<mesh_Type> (containerPointsGivenFlag, containerPointsWithAppliedCurrent, activationTime, deltaT, numberLocalSources, * (solver -> fullMeshPtr() ), Comm );
376 
377 
378 
379  //********************************************//
380  // Setting up the time data //
381  //********************************************//
382  solver -> setParameters ( monodomainList );
383 
384  //********************************************//
385  // Create a fiber direction //
386  //********************************************//
387  if ( Comm->MyPID() == 0 )
388  {
389  std::cout << "\nSetting fibers: " ;
390  }
391 
392  VectorSmall<3> fibers;
393  fibers[0] = 0.0;
394  fibers[1] = 0.0;
395  fibers[2] = 1.0;
396  solver -> setupFibers ( fibers );
397 
398  if ( Comm->MyPID() == 0 )
399  {
400  std::cout << "Done! \n" ;
401  }
402 
403  //********************************************//
404  // Create the global matrix: mass + stiffness //
405  //********************************************//
406  if ( Comm->MyPID() == 0 )
407  {
408  std::cout << "\nSetup operators: " ;
409  }
410 
411  bool lumpedMass = monodomainList.get ("LumpedMass", true);
412  if ( lumpedMass)
413  {
414  solver -> setupLumpedMassMatrix();
415  }
416  else
417  {
418  solver -> setupMassMatrix();
419  }
420 
421 
422  solver -> setupStiffnessMatrix ( solver -> diffusionTensor() );
423  solver -> setupGlobalMatrix();
424  if ( Comm->MyPID() == 0 )
425  {
426  std::cout << "Done! \n" ;
427  }
428 
429  //********************************************//
430  // Creating exporters to save the solution //
431  //********************************************//
432  ExporterHDF5< RegionMesh <LinearTetra> > exporter;
433 
434  solver -> setupExporter ( exporter, monodomainList.get ("OutputFile", "Solution") );
435  exporter.setPostDir (problemFolder);
436  solver -> exportSolution ( exporter, 0);
437 
438  //********************************************//
439  // Activation time //
440  //********************************************//
441  vectorPtr_Type activationTimeVector ( new vector_Type ( solver -> potentialPtr() -> map() ) );
442  *activationTimeVector = -1.0;
443 
444  ExporterHDF5< RegionMesh <LinearTetra> > activationTimeExporter;
445  activationTimeExporter.setMeshProcId (solver -> localMeshPtr(), solver -> commPtr() ->MyPID() );
446  activationTimeExporter.addVariable (ExporterData<mesh_Type>::ScalarField, "Activation Time",
447  solver -> feSpacePtr(), activationTimeVector, UInt (0) );
448  activationTimeExporter.setPrefix ("ActivationTime");
449  activationTimeExporter.setPostDir (problemFolder);
450 
451  //********************************************//
452  // Solving the system //
453  //********************************************//
454  if ( Comm->MyPID() == 0 )
455  {
456  std::cout << "\nstart solving: " ;
457  }
458 
459  Real dt = monodomainList.get ("timeStep", 0.1);
460  Real TF = monodomainList.get ("endTime", 150.0);
461  Int iter = monodomainList.get ("saveStep", 1.0) / dt;
462  Int k (0);
463 
464  Real timeReac = 0.0;
465  Real timeDiff = 0.0;
466  Real timeReacDiff = 0.0;
467  LifeChrono chrono;
468 
469  std::string solutionMethod = monodomainList.get ("solutionMethod", "splitting");
470 
471  std::vector<Real> statesExcitationModel (excitationModel->Size(), 0);
472  std::vector<Real> rhsExcitationModel (excitationModel->Size(), 0);
473  std::vector<Real> valueAppliedCurrent (TF / dt, 0);
474  std::vector<UInt> shiftVector (TF / dt, -1);
475  excitationModel->initialize (statesExcitationModel);
476  statesExcitationModel[0] = -70.0;
477  statesExcitationModel[1] = excitationModel->mInf (-70.0);
478  statesExcitationModel[2] = excitationModel->nInf (-70.0);
479  statesExcitationModel[3] = excitationModel->hInf (-70.0);
480  int localIndexTime (0);
481  for ( Real t = 0.0; t < TF; )
482  {
483  // solver -> setAppliedCurrentFromFunction ( stimulus, t );
484 
485 
486  excitationModel->computeGatingVariablesWithRushLarsen (statesExcitationModel, dt);
487  statesExcitationModel.at (0) = statesExcitationModel.at (0) + dt * (excitationModel->computeLocalPotentialRhs ( statesExcitationModel) );
488  valueAppliedCurrent[localIndexTime] = excitationModel->Itotal();
489  localIndexTime++;
490  //ElectrophysiologyUtility::appliedCurrentPointsWithinRadius<mesh_Type>(junction,Radius,solver -> appliedCurrentPtr(),excitationModel->Itotal()/85.7,solver -> fullMeshPtr() );
491 
492 
493  //ElectrophysiologyUtility::applyCurrentGivenSetOfPoints<ID>(containerPointsWithAppliedCurrent,solver -> appliedCurrentPtr(), excitationModel->Itotal() );//
494  ElectrophysiologyUtility::applyCurrentGivenSetOfPoints<ID> (containerPointsWithAppliedCurrent, activationTime, solver -> appliedCurrentPtr(), valueAppliedCurrent, shiftVector, t);
495  if ( solutionMethod == "splitting" )
496  {
497  chrono.reset();
498  chrono.start();
499  if (ionic_model != "MinimalModel" && ionic_model != "HodgkinHuxley")
500  {
501  solver->solveOneReactionStepRL();
502  }
503  else
504  {
505  solver->solveOneReactionStepFE();
506  }
507  chrono.stop();
508 
509  timeReac += chrono.globalDiff ( *Comm );
510 
511  (*solver->rhsPtrUnique() ) *= 0.0;
512  solver->updateRhs();
513 
514  chrono.reset();
515  chrono.start();
516  solver->solveOneDiffusionStepBE();
517  chrono.stop();
518  timeDiff += chrono.globalDiff ( *Comm );
519  }
520  else if ( solutionMethod == "ICI" )
521  {
522  chrono.reset();
523  chrono.start();
524  if (ionic_model != "MinimalModel" && ionic_model != "HodgkinHuxley")
525  {
526  solver -> solveOneStepGatingVariablesRL();
527  }
528  else
529  {
530  solver -> solveOneStepGatingVariablesFE();
531  }
532  solver -> solveOneICIStep();
533  chrono.stop();
534  timeReacDiff += chrono.globalDiff ( *Comm );
535  }
536  else if ( solutionMethod == "SVI" )
537  {
538  chrono.reset();
539  chrono.start();
540  if (ionic_model != "MinimalModel" && ionic_model != "HodgkinHuxley")
541  {
542  solver -> solveOneStepGatingVariablesRL();
543  }
544  else
545  {
546  solver -> solveOneStepGatingVariablesFE();
547  }
548  solver -> solveOneSVIStep();
549  chrono.stop();
550  timeReacDiff += chrono.globalDiff ( *Comm );
551  }
552 
553  //register activation time
554  k++;
555  t = t + dt;
556  solver -> registerActivationTime (*activationTimeVector, t, 0.95);
557 
558  if ( k % iter == 0 )
559  {
560  solver -> exportSolution (exporter, t);
561  }
562  if ( Comm->MyPID() == 0 )
563  {
564  std::cout << "\n\n\nActual time : " << t << std::endl << std::endl << std::endl;
565  }
566  }
567 
568  Real normSolution = ( ( solver -> globalSolution().at (0) )->norm2() );
569  if ( Comm->MyPID() == 0 )
570  {
571  std::cout << "2-norm of potential solution: " << normSolution << std::endl;
572  }
573 
574  exporter.closeFile();
575  activationTimeExporter.postProcess (0);
576  activationTimeExporter.closeFile();
577 
578  if ( Comm->MyPID() == 0 )
579  {
580  std::cout << "Exporting fibers: " << std::endl;
581  }
582 
583  //********************************************//
584  // Saving Fiber direction to file //
585  //********************************************//
586  solver -> exportFiberDirection();
587 
588 
589  if ( Comm->MyPID() == 0 )
590  {
591  chronoinitialsettings.stop();
592  std::cout << "\n\n\nTotal lapsed time : " << chronoinitialsettings.diff() << std::endl;
593  if ( solutionMethod == "splitting" )
594  {
595  std::cout << "Diffusion time : " << timeDiff << std::endl;
596  std::cout << "Reaction time : " << timeReac << std::endl;
597  }
598  else if ( solutionMethod == "ICI" )
599  {
600  std::cout << "Solution time : " << timeReacDiff << std::endl;
601  }
602  else if ( solutionMethod == "SVI" )
603  {
604  std::cout << "Solution time : " << timeReacDiff << std::endl;
605  }
606 
607  std::cout << "\n\nThank you for using ETA_MonodomainSolver.\nI hope to meet you again soon!\n All the best for your simulation :P\n " ;
608  }
609  MPI_Barrier (MPI_COMM_WORLD);
610  MPI_Finalize();
611 
612  return ( EXIT_SUCCESS );
613 }
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
virtual std::vector< std::vector< Real > > getJac(const std::vector< Real > &v, Real h=1.0e-8)
This methods computes the Jacobian numerically.
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
Real PacingProtocolMM(const Real &t, const Real &x, const Real &y, const Real &z, const ID &)
Real & operator[](UInt const &i)
Operator [].
uint32_type ID
IDs.
Definition: LifeV.hpp:194
double Real
Generic real data.
Definition: LifeV.hpp:175
Real PacingProtocolHH(const Real &t, 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 &)
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191