LifeV
lifev/electrophysiology/examples/example_ECG/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 0D test with the Negroni Lascano model of 1996.
30 
31  @date 01−2013
32  @author Simone Rossi <simone.rossi@epfl.ch>
33 
34  @contributor
35  @mantainer Simone Rossi <simone.rossi@epfl.ch>
36  */
37 
38 // Tell the compiler to ignore specific kind of warnings:
39 #pragma GCC diagnostic ignored "-Wunused-variable"
40 #pragma GCC diagnostic ignored "-Wunused-parameter"
41 
42 #include <Epetra_ConfigDefs.h>
43 #ifdef EPETRA_MPI
44 #include <mpi.h>
45 #include <Epetra_MpiComm.h>
46 #else
47 #include <Epetra_SerialComm.h>
48 #endif
49 
50 //Tell the compiler to restore the warning previously silented
51 #pragma GCC diagnostic warning "-Wunused-variable"
52 #pragma GCC diagnostic warning "-Wunused-parameter"
53 
54 
55 
56 #include <fstream>
57 #include <string>
58 
59 #include <lifev/core/array/VectorSmall.hpp>
60 
61 #include <lifev/core/array/VectorEpetra.hpp>
62 #include <lifev/core/array/MatrixEpetra.hpp>
63 #include <lifev/core/array/MapEpetra.hpp>
64 #include <lifev/core/mesh/MeshData.hpp>
65 #include <lifev/core/mesh/MeshPartitioner.hpp>
66 #include <lifev/core/filter/ExporterEnsight.hpp>
67 #include <lifev/core/filter/ExporterHDF5.hpp>
68 #include <lifev/core/filter/ExporterEmpty.hpp>
69 
70 #include <lifev/core/algorithm/LinearSolver.hpp>
71 #include <lifev/electrophysiology/solver/ElectroETAMonodomainSolver.hpp>
72 
73 #include <lifev/core/filter/ExporterEnsight.hpp>
74 #ifdef HAVE_HDF5
75 #include <lifev/core/filter/ExporterHDF5.hpp>
76 #endif
77 #include <lifev/core/filter/ExporterEmpty.hpp>
78 
79 #include <lifev/electrophysiology/solver/IonicModels/IonicAlievPanfilov.hpp>
80 #include <lifev/electrophysiology/solver/IonicModels/IonicMinimalModel.hpp>
81 #include <lifev/core/LifeV.hpp>
82 
83 #include <Teuchos_RCP.hpp>
84 #include <Teuchos_ParameterList.hpp>
85 #include "Teuchos_XMLParameterListHelpers.hpp"
86 // ---------------------------------------------------------------
87 // In order to use the ETA framework, a special version of the
88 // FESpace structure must be used. It is called ETFESpace and
89 // has basically the same role as the FESpace.
90 // ---------------------------------------------------------------
91 
92 #include <lifev/eta/fem/ETFESpace.hpp>
93 #include <lifev/eta/expression/Integrate.hpp>
94 
95 //--------------------------------------------------------
96 // For the pseudo- ECG
97 //--------------------------------------------------------
98 #include <lifev/electrophysiology/examples/example_ECG/Norm.hpp>
99 #include <lifev/core/solver/ADRAssembler.hpp>
100 #include <lifev/core/algorithm/LinearSolver.hpp>
101 #include <lifev/core/algorithm/PreconditionerML.hpp>
102 
103 // ---------------------------------------------------------------
104 // The most important file to include is the Integrate.hpp file
105 // which contains all the definitions required to perform the
106 // different integrations.
107 // ---------------------------------------------------------------
108 
109 //#include <lifev/eta/expression/Integrate.hpp>
110 //
111 //#include <lifev/eta/expression/ExpressionDot.hpp>
112 
113 
114 using namespace LifeV;
115 
116 // Choice of the fibers direction : ||.||=1
117 Real Fibers (const Real& /*t*/, const Real& /*x*/, const Real& /*y*/, const Real& z, const ID& i)
118 {
119  Teuchos::ParameterList monodomainList = * ( Teuchos::getParametersFromXmlFile ( "MonodomainSolverParamList.xml" ) );
120  Real zmin = 0.0;
121  Real zmax = monodomainList.get ("domain_Z", 1. ); // 1.0;
122  Real L = zmax - zmin;
123  Real thetamin = M_PI / 3.;
124  Real thetamax = -M_PI / 3.;
125 
126  Real ztheta = (L - z) / L;
127  Real theta = (thetamax - thetamin) * ztheta + thetamin;
128 
129  switch (i)
130  {
131  case 0:
132  return std::cos (theta); // x_fib; //y/N; //std::sqrt (2.0) / 2.0; //
133  break;
134  case 1:
135  return std::sin (theta); // y_fib; //-x/N; //std::sqrt (2.0) / 2.0; //
136  break;
137  case 2:
138  return 0.0;
139  break;
140  default:
141  return 0.0;
142  break;
143  }
144 }
145 
146 Real Stimulus2 (const Real& /*t*/, const Real& x, const Real& y, const Real& z, const ID& /*i*/)
147 {
148  Teuchos::ParameterList monodomainList = * ( Teuchos::getParametersFromXmlFile ( "MonodomainSolverParamList.xml" ) );
149  Real pacingSite_X = monodomainList.get ("pacingSite_X", 0.);
150  Real pacingSite_Y = monodomainList.get ("pacingSite_Y", 0.);
151  Real pacingSite_Z = monodomainList.get ("pacingSite_Z", 0. );
152  Real stimulusRadius = 0.1; // monodomainList.get ("stimulusRadius", 0.1);
153 
154  if ( ( ( x - pacingSite_X ) * ( x - pacingSite_X ) + ( y - pacingSite_Y ) * ( y - pacingSite_Y ) + ( z - pacingSite_Z ) * ( z - pacingSite_Z ) )
155  <= ( stimulusRadius * stimulusRadius ) )
156  {
157  return 1.0;
158  }
159  else
160  {
161  return 0.0;
162  }
163 }
164 
165 
166 Real PacingProtocol ( const Real& /*t*/, const Real& x, const Real& y, const Real& z, const ID& /*id*/)
167 {
168  Teuchos::ParameterList monodomainList = * ( Teuchos::getParametersFromXmlFile ( "MonodomainSolverParamList.xml" ) );
169  Real pacingSite_X = monodomainList.get ("pacingSite_X", 0.);
170  Real pacingSite_Y = monodomainList.get ("pacingSite_Y", 0.);
171  Real pacingSite_Z = monodomainList.get ("pacingSite_Z", 1.);
172  Real stimulusRadius = monodomainList.get ("stimulusRadius", 0.1);
173  Real stimulusValue = monodomainList.get ("stimulusValue", 1.);
174 
175  Real returnValue1;
176 
177  // --- Pacing protocol parameters -----------------------------------
178 
179  std::vector<double> returnPeriods;
180  std::vector<double> returnStimulusTime;
181 
182  if ( ( ( x - pacingSite_X ) * ( x - pacingSite_X ) + ( y - pacingSite_Y ) * ( y - pacingSite_Y ) + ( z - pacingSite_Z ) * ( z - pacingSite_Z ) )
183  <= ( stimulusRadius * stimulusRadius ) )
184  {
185  returnValue1 = stimulusValue;
186  }
187  else
188  {
189  returnValue1 = 0.;
190  }
191 
192  Real returnValue = returnValue1;
193  return returnValue;
194 }
195 
196 
197 Int main ( Int argc, char** argv )
198 {
199  //! Initializing Epetra communicator
200  MPI_Init (&argc, &argv);
201  {
202  std::shared_ptr<Epetra_Comm> Comm ( new Epetra_MpiComm (MPI_COMM_WORLD) );
203  if ( Comm->MyPID() == 0 )
204  {
205  std::cout << "% using MPI" << std::endl;
206  }
207 
208  //********************************************//
209  // Starts the chronometer. //
210  //********************************************//
211  // LifeChrono chronoinitialsettings;
212  // chronoinitialsettings.start();
213 
214  typedef RegionMesh<LinearTetra> mesh_Type;
215  typedef std::shared_ptr<mesh_Type> meshPtr_Type;
216  typedef std::shared_ptr<VectorEpetra> vectorPtr_Type;
217  typedef FESpace< mesh_Type, MapEpetra > feSpace_Type;
218  typedef std::shared_ptr<feSpace_Type> feSpacePtr_Type;
219  typedef std::function < Real (const Real& /*t*/,
220  const Real & x,
221  const Real & y,
222  const Real& /*z*/,
223  const ID& /*i*/ ) > function_Type;
224  typedef VectorEpetra vector_Type;
225  typedef MatrixEpetra<Real> matrix_Type;
226  typedef LifeV::Preconditioner basePrec_Type;
227  typedef std::shared_ptr<basePrec_Type> basePrecPtr_Type;
228  typedef LifeV::PreconditionerML prec_Type;
229  typedef std::shared_ptr<prec_Type> precPtr_Type;
230  typedef ElectroETAMonodomainSolver< mesh_Type, IonicMinimalModel > monodomainSolver_Type;
231  typedef std::shared_ptr< monodomainSolver_Type > monodomainSolverPtr_Type;
232 
233  typedef std::shared_ptr< LifeV::Exporter<LifeV::RegionMesh<LifeV::LinearTetra> > > filterPtr_Type;
234  typedef LifeV::ExporterHDF5< RegionMesh<LinearTetra> > hdf5Filter_Type;
235  typedef std::shared_ptr<hdf5Filter_Type> hdf5FilterPtr_Type;
236  typedef ExporterData<mesh_Type> exporterData_Type;
237  typedef Exporter< mesh_Type > IOFile_Type;
238  typedef std::shared_ptr< IOFile_Type > IOFilePtr_Type;
239  typedef ExporterHDF5< mesh_Type > hdf5IOFile_Type;
240 
241  //********************************************//
242  // Import parameters from an xml list. Use //
243  // Teuchos to create a list from a given file //
244  // in the execution directory. //
245  //********************************************//
246 
247  if ( Comm->MyPID() == 0 )
248  {
249  std::cout << "Importing parameters list...";
250  }
251  Teuchos::ParameterList monodomainList = * ( Teuchos::getParametersFromXmlFile ( "MonodomainSolverParamList.xml" ) );
252  if ( Comm->MyPID() == 0 )
253  {
254  std::cout << " Done!" << std::endl;
255  }
256 
257  //********************************************//
258  // Creates a new model object representing the//
259  // model from Aliev and Panfilov 1996. The //
260  // model input are the parameters. Pass the //
261  // parameter list in the constructor //
262  //********************************************//
263  if ( Comm->MyPID() == 0 )
264  {
265  std::cout << "Building Constructor for Aliev Panfilov Model with parameters ... ";
266  }
267  std::shared_ptr<IonicMinimalModel> model ( new IonicMinimalModel() );
268  if ( Comm->MyPID() == 0 )
269  {
270  std::cout << " Done!" << std::endl;
271  }
272 
273  //********************************************//
274  // In the parameter list we need to specify //
275  // the mesh name and the mesh path. //
276  //********************************************//
277  std::string meshName = monodomainList.get ("mesh_name", "lid16.mesh");
278  std::string meshPath = monodomainList.get ("mesh_path", "./");
279 
280  //********************************************//
281  // We need the GetPot datafile for to setup //
282  // the preconditioner. //
283  //********************************************//
284  GetPot command_line (argc, argv);
285  const std::string data_file_name = command_line.follow ("data", 2, "-f", "--file");
286  GetPot dataFile (data_file_name);
287 
288  // +-----------------------------------------------+
289  // | Loading the mesh |
290  // +-----------------------------------------------+
291  if ( Comm->MyPID() == 0 )
292  {
293  std::cout << std::endl << "[Loading the mesh]" << std::endl;
294  }
295 
296  meshPtr_Type fullMeshPtr ( new mesh_Type ( Comm ) );
297 
298  std::vector<Real> meshDim (3, 0);
299  meshDim[0] = monodomainList.get ("meshDim_X", 10 );
300  meshDim[1] = monodomainList.get ("meshDim_Y", 10 );
301  meshDim[2] = monodomainList.get ("meshDim_Z", 10 );
302  std::vector<Real> domain (3, 0);
303  domain[0] = monodomainList.get ("domain_X", 1. );
304  domain[1] = monodomainList.get ("domain_Y", 1. );
305  domain[2] = monodomainList.get ("domain_Z", 1. );
306 
307  // Building the mesh from the source
308  regularMesh3D ( *fullMeshPtr,
309  1,
310  meshDim[0], meshDim[1], meshDim[2],
311  false,
312  domain[0], domain[1], domain[2],
313  0.0, 0.0, 0.0 );
314 
315  if ( Comm->MyPID() == 0 )
316  {
317  std::cout << "Mesh size : " << MeshUtility::MeshStatistics::computeSize ( *fullMeshPtr ).maxH << std::endl;
318  }
319  if ( Comm->MyPID() == 0 )
320  {
321  std::cout << "Partitioning the mesh ... " << std::endl;
322  }
323  meshPtr_Type meshPtr;
324  {
325  MeshPartitioner< mesh_Type > meshPart ( fullMeshPtr, Comm );
326  meshPtr = meshPart.meshPartition();
327  }
328  fullMeshPtr.reset(); //Freeing the global mesh to save memory
329 
330  //********************************************//
331  // We create the solvers to solve with: //
332  // Operator Splitting method //
333  //********************************************//
334  if ( Comm->MyPID() == 0 )
335  {
336  std::cout << "Building Monodomain Solvers... ";
337  }
338 
339  monodomainSolverPtr_Type splitting ( new monodomainSolver_Type ( dataFile, model, meshPtr ) );
340  const feSpacePtr_Type FESpacePtr = splitting->feSpacePtr(); //FE Space
341 
342  if ( Comm->MyPID() == 0 )
343  {
344  std::cout << " Splitting solver done... ";
345  }
346 
347  function_Type pacing = &PacingProtocol;
348  function_Type f = &Stimulus2;
349 
350  // //***********************************************//
351  // // RESTART Protocol //
352  // //***********************************************//
353  //
354  // string filenameStart = monodomainList.get ("StartFile", "MMStartSplitting" );
355  // std::string sol ( filenameStart ); // name of the file from which we want to restart
356  // string iterationString = monodomainList.get ("StartIteration", "00050" );
357  //
358  //
359  // // Setting up the importer
360  // filterPtr_Type importer ( new hdf5Filter_Type( ) );
361  // importer->setMeshProcId ( splitting -> localMeshPtr(), Comm -> MyPID() );
362  // importer->setPrefix ( sol );
363  //
364  // // Import the value of the potential and gating variable
365  // monodomainSolver_Type::vectorPtr_Type newSol;
366  // newSol.reset(new VectorEpetra ( splitting -> feSpacePtr() -> map(), LifeV::Unique ));
367  //
368  // exporterData_Type ImportDataPotential (exporterData_Type::ScalarField, ("Variable0." + iterationString) , splitting -> feSpacePtr(),
369  // newSol, UInt (0), exporterData_Type::UnsteadyRegime);
370  //
371  // monodomainSolver_Type::vectorPtr_Type newGating1;
372  // newGating1.reset(new VectorEpetra ( splitting -> feSpacePtr() -> map(), LifeV::Unique ));
373  //
374  // exporterData_Type ImportDataGating1 (exporterData_Type::ScalarField, ("Variable1." + iterationString), splitting -> feSpacePtr(),
375  // newGating1, UInt (0), exporterData_Type::UnsteadyRegime);
376  //
377  // monodomainSolver_Type::vectorPtr_Type newGating2;
378  // newGating2.reset(new VectorEpetra ( splitting -> feSpacePtr() -> map(), LifeV::Unique ));
379  //
380  // exporterData_Type ImportDataGating2 (exporterData_Type::ScalarField, ( "Variable2." + iterationString), splitting -> feSpacePtr(),
381  // newGating2, UInt (0), exporterData_Type::UnsteadyRegime);
382  //
383  // monodomainSolver_Type::vectorPtr_Type newGating3;
384  // newGating3.reset(new VectorEpetra ( splitting -> feSpacePtr() -> map(), LifeV::Unique ));
385  //
386  // exporterData_Type ImportDataGating3 (exporterData_Type::ScalarField, ( "Variable3." + iterationString), splitting -> feSpacePtr(),
387  // newGating3, UInt (0), exporterData_Type::UnsteadyRegime);
388  //
389  // importer->readVariable ( ImportDataPotential );
390  // importer->readVariable( ImportDataGating1 );
391  // importer->readVariable( ImportDataGating2 );
392  // importer->readVariable( ImportDataGating3 );
393  //
394  // //********************************************//
395  // // Setting up the initial condition form //
396  // // a given function. //
397  // //********************************************//
398  // if ( Comm->MyPID() == 0 )
399  // {
400  // std::cout << "\nInitializing potential: " ;
401  // }
402  //
403  // splitting-> setPotentialPtr(newSol);
404  // * ( splitting -> globalSolution().at (1) ) = *newGating1;
405  // * ( splitting -> globalSolution().at (2) ) = *newGating2;
406  // * ( splitting -> globalSolution().at (3) ) = *newGating3;
407 
408  //*****************************************************************************************************
409  // END OF RESTART
410  //*****************************************************************************************************
411 
412  //********************************************//
413  // Setting up the initial condition form //
414  // a given function. //
415  //********************************************//
416  if ( Comm->MyPID() == 0 )
417  {
418  std::cout << "\nInitializing potential: " ;
419  }
420  //Compute the potential at t0
421 
422  splitting -> setPotentialFromFunction ( f );
423  //setting up initial conditions
424  * ( splitting -> globalSolution().at (1) ) = 1.0;
425  * ( splitting -> globalSolution().at (2) ) = 1.0;
426  * ( splitting -> globalSolution().at (3) ) = 0.021553043080281;
427 
428  // APD calculation variables
429  Int sz = 0;
430  sz = (* (splitting->globalSolution().at (0) ) ).size();
431  Real threshold = monodomainList.get ("threshold", 0.1);
432  Real trep = 0.;
433  vector_Type tact = (* (splitting->globalSolution().at (0) ) );
434  tact *= 0;
435  vector_Type apd = tact;
436  vector_Type delta_apd = tact;
437  vector_Type previouspotential = (* (splitting->globalSolution().at (0) ) );
438 
439 
440 
441  if ( Comm->MyPID() == 0 )
442  {
443  std::cout << "Done! \n" ;
444  }
445 
446  //********************************************//
447  // Setting up the pacing protocol //
448  //********************************************//
449  bool PacingProtocol = monodomainList.get ("pacingProtocol", false);
450  std::vector<double> returnStimulusTime;
451  std::vector<double> returnPeriods;
452 
453  Real stimulusStart = monodomainList.get ("stimulusStart", 0.);
454  Real stimulusStop = monodomainList.get ("stimulusStop", 0.05);
455  Int stimulusNumber;
456  Int NumberPacingPeriods;
457 
458  int i (0);
459 
460  if (PacingProtocol)
461  {
462  Real pacingPeriod = monodomainList.get ("pacingPeriod", 500.);
463  Real pacingPeriodMin = monodomainList.get ("pacingPeriodMin", 400.);
464  Real pacingDelta = monodomainList.get ("pacingDelta", 0.);
465  stimulusNumber = monodomainList.get ("stimulusNumber", 1);
466  NumberPacingPeriods = (pacingPeriod - pacingPeriodMin) / pacingDelta;
467  //--- Pacing method
468  if ( pacingDelta > 0 ) // IF pacing
469  {
470  for (int k = 0; k <= NumberPacingPeriods - 1; k++ )
471  {
472  for (i = stimulusNumber * k; i <= stimulusNumber * (k + 1) - 1; i++)
473  {
474  returnPeriods.push_back ( pacingPeriod - k * pacingDelta );
475  if ( i == 0 )
476  {
477  returnStimulusTime.push_back ( returnPeriods[0] );
478  }
479  else
480  {
481  returnStimulusTime.push_back ( returnStimulusTime[i - 1] + returnPeriods[i] );
482  }
483  }
484  }
485  }
486  }
487  else
488  {
489  returnPeriods.push_back ( monodomainList.get ("stimulus0", 500.) );
490  returnPeriods.push_back ( monodomainList.get ("stimulus1", 450.) );
491  returnPeriods.push_back ( monodomainList.get ("stimulus2", 425.) );
492  returnPeriods.push_back ( monodomainList.get ("stimulus3", 400.) );
493  returnPeriods.push_back ( monodomainList.get ("stimulus4", 375.) );
494  returnPeriods.push_back ( monodomainList.get ("stimulus5", 350.) );
495  returnPeriods.push_back ( monodomainList.get ("stimulus6", 325.) );
496  returnPeriods.push_back ( monodomainList.get ("stimulus7", 300.) );
497  returnPeriods.push_back ( monodomainList.get ("stimulus8", 275.) );
498  returnPeriods.push_back ( monodomainList.get ("stimulus9", 275.) );
499  returnPeriods.push_back ( monodomainList.get ("stimulus10", 275.) );
500  returnPeriods.push_back ( monodomainList.get ("stimulus11", 275.) );
501  returnPeriods.push_back ( monodomainList.get ("stimulus12", 450.) );
502  returnPeriods.push_back ( monodomainList.get ("stimulus13", 400.) );
503  returnPeriods.push_back ( monodomainList.get ("stimulus14", 375.) );
504  returnPeriods.push_back ( monodomainList.get ("stimulus15", 350.) );
505  returnPeriods.push_back ( monodomainList.get ("stimulus16", 325.) );
506  returnPeriods.push_back ( monodomainList.get ("stimulus17", 300.) );
507  returnPeriods.push_back ( monodomainList.get ("stimulus18", 275.) );
508  returnPeriods.push_back ( monodomainList.get ("stimulus19", 275.) );
509  returnPeriods.push_back ( monodomainList.get ("stimulus20", 275.) );
510  returnPeriods.push_back ( monodomainList.get ("stimulus21", 275.) );
511  returnPeriods.push_back ( monodomainList.get ("stimulus22", 450.) );
512  returnPeriods.push_back ( monodomainList.get ("stimulus23", 400.) );
513  returnPeriods.push_back ( monodomainList.get ("stimulus24", 375.) );
514  returnPeriods.push_back ( monodomainList.get ("stimulus25", 350.) );
515  returnPeriods.push_back ( monodomainList.get ("stimulus26", 325.) );
516  returnPeriods.push_back ( monodomainList.get ("stimulus27", 300.) );
517  returnPeriods.push_back ( monodomainList.get ("stimulus28", 275.) );
518  returnPeriods.push_back ( monodomainList.get ("stimulus29", 275.) );
519  returnPeriods.push_back ( monodomainList.get ("stimulus30", 275.) );
520 
521  NumberPacingPeriods = monodomainList.get ("NbStimulusPeriod", 12);
522 
523  stimulusNumber = 1;
524  for (int k = 0; k <= NumberPacingPeriods - 1; k++ )
525  {
526  if (k == 0)
527  {
528  returnStimulusTime.push_back ( returnPeriods[0] );
529  }
530  else
531  {
532  returnStimulusTime.push_back ( returnStimulusTime[k - 1] + returnPeriods[k] );
533  }
534  }
535  }
536  //*******************************************//
537  // Setting up the pseudo-ECG //
538  //*******************************************//
539  Real ecg_position_X = monodomainList.get ("ecg_position_X", 1.);
540  Real ecg_position_Y = monodomainList.get ("ecg_position_Y", 1.);
541  Real ecg_position_Z = monodomainList.get ("ecg_position_Z", 0.5);
542  vector_Type ecgDistance = (* (splitting->globalSolution().at (0) ) ) ;
543  ecgDistance *= 0.;
544  FESpacePtr->interpolate ( static_cast<function_Type> ( Norm::f ), ecgDistance, 0.0 );
545  Norm::setPosition ( ecg_position_X , ecg_position_Y , ecg_position_Z ); // Set electrode position
546 
547  Real pseudoEcgReal (0.);
548  Real Global_pseudoEcgReal (0.);
549  vector_Type solutionLaplacian = ( (* (splitting->globalSolution().at (0) ) ) );
550  vector_Type pseudoEcgVec = ( (* (splitting->globalSolution().at (0) ) ) );
551 
552  // Discrete Laplacian matrix
553  // setting up the assembler
554  ADRAssembler<mesh_Type, matrix_Type, vector_Type> adrAssembler;
555  adrAssembler.setup ( FESpacePtr, FESpacePtr );
556  // define the matrices
557  std::shared_ptr<matrix_Type> systemMatrixL ( new matrix_Type ( FESpacePtr->map() ) );
558  std::shared_ptr<matrix_Type> systemMatrixM ( new matrix_Type ( FESpacePtr->map() ) );
559  std::shared_ptr<vector_Type> rhs_Laplacian ( new vector_Type ( FESpacePtr->map() ) );
560  std::shared_ptr<vector_Type> pseudoEcgVec_ptr ( new vector_Type ( FESpacePtr->map() ) );
561 
562  // fill the matrix
563  adrAssembler.addDiffusion ( systemMatrixL, -1.0 );
564  adrAssembler.addMass ( systemMatrixM, 1.0 );
565  // closed
566  systemMatrixL->globalAssemble();
567  systemMatrixM->globalAssemble();
568 
569  // uncomment to check the matrices with MATLAB
570  // matrix_Type LaplacianMatrix ( *systemMatrixL );
571  // matrix_Type MassMatrix ( *systemMatrixM );
572  // LaplacianMatrix.spy("matriceL_check");
573  // MassMatrix.spy("matriceM_check");
574  //********************************************//
575  // Setting up the time data //
576  //********************************************//
577  splitting -> setParameters ( monodomainList );
578 
579  //********************************************//
580  // Create a fiber direction //
581  //********************************************//
582  VectorSmall<3> fibers;
583  fibers[0] = monodomainList.get ("fiber_X", std::sqrt (2.0) / 2.0 );
584  fibers[1] = monodomainList.get ("fiber_Y", std::sqrt (2.0) / 2.0 );
585  fibers[2] = monodomainList.get ("fiber_Z", 0.0 );
586 
587  splitting ->setupFibers (fibers);
588 
589  //********************************************//
590  // Create the global matrix: mass + stiffness //
591  //********************************************//
592  splitting -> setupLumpedMassMatrix();
593  splitting -> setupStiffnessMatrix();
594  splitting -> setupGlobalMatrix();
595 
596  //********************************************//
597  // Creating exporters to save the solution //
598  //********************************************//
599  ExporterHDF5< RegionMesh <LinearTetra> > exporterSplitting;
600  std::string filenameSplitting = monodomainList.get ("OutputFile", "MinMod" );
601  filenameSplitting += "Splitting";
602  splitting -> setupPotentialExporter ( exporterSplitting, filenameSplitting );
603 
604  ExporterHDF5< RegionMesh <LinearTetra> > exporterSplittingRestart;
605  std::string filenameSplittingLast = monodomainList.get ("OutputFile", "MinMod" );
606  filenameSplittingLast += "RESTART";
607  splitting -> setupExporter ( exporterSplittingRestart, filenameSplittingLast );
608 
609  vectorPtr_Type APDptr ( new vector_Type (apd, Repeated ) );
610  exporterSplitting.addVariable ( ExporterData<mesh_Type>::ScalarField, "apd", FESpacePtr,
611  APDptr, UInt (0) );
612 
613  vectorPtr_Type DELTA_APDptr ( new vector_Type (delta_apd, Repeated ) );
614  exporterSplitting.addVariable ( ExporterData<mesh_Type>::ScalarField, "delta_apd", FESpacePtr,
615  DELTA_APDptr, UInt (0) );
616 
617  *APDptr = apd;
618  *DELTA_APDptr = delta_apd;
619 
620  std::ofstream output ("ecg_output.txt");
621 
622  //**************************************************//
623  // Solver initialization for the discrete Laplacian //
624  //**************************************************//
625  if ( Comm->MyPID() == 0 )
626  {
627  std::cout << std::endl << "[Solvers initialization]" << std::endl;
628  }
629  prec_Type* precRawPtr;
630  basePrecPtr_Type precPtr;
631  precRawPtr = new prec_Type;
632  precRawPtr->setDataFromGetPot ( dataFile, "prec" );
633  precPtr.reset ( precRawPtr );
634  if ( Comm->MyPID() == 0 )
635  {
636  std::cout << "Setting up LinearSolver (Belos)... " << std::flush;
637  }
638  Teuchos::RCP< Teuchos::ParameterList > belosList2 = Teuchos::rcp ( new Teuchos::ParameterList );
639  belosList2 = Teuchos::getParametersFromXmlFile ( "SolverParamList2.xml" );
640  LinearSolver linearSolver2;
641  linearSolver2.setCommunicator ( Comm );
642  linearSolver2.setParameters ( *belosList2 );
643  linearSolver2.setPreconditioner ( precPtr );
644  if ( Comm->MyPID() == 0 )
645  {
646  std::cout << "done" << std::endl;
647  }
648  linearSolver2.showMe();
649 
650  //********************************************//
651  // Solving the system //
652  //********************************************//
653  if ( Comm->MyPID() == 0 )
654  {
655  std::cout << "\nstart solving: " ;
656  }
657 
658  Real Savedt = monodomainList.get ("saveStep", 0.1);
659  Real timeStep = monodomainList.get ("timeStep", 0.01);
660  Real endTime = monodomainList.get ("endTime", 10.);
661  Real initialTime = monodomainList.get ("initialTime", 0.);
662 
663  vectorPtr_Type previousPotential0Ptr ( new vector_Type ( FESpacePtr->map() ) );
664  * (previousPotential0Ptr) = * (splitting->globalSolution().at (0) );
665  int control = 0;
666  int iter ( (Savedt / timeStep) + 1e-9);
667  int iterRestart ( (500 / timeStep) + 1e-9);
668  int nbTimeStep (1);
669  int k (0);
670  if (endTime > timeStep)
671  {
672  for (Real t = initialTime; t < endTime;)
673  {
674 
675  // APD calculation
676  previouspotential = (* (splitting->globalSolution().at (0) ) );
677  //--------------------------------------
678  // ECG initialization
679  pseudoEcgReal = 0.;
680  pseudoEcgVec_ptr.reset ( new vector_Type ( FESpacePtr->map(), Unique ) );
681  rhs_Laplacian.reset ( new vector_Type ( FESpacePtr->map(), Unique ) );
682  //-----------------------------------------------------------------
683 
684  control = 0;
685 
686  t += timeStep;
687  for (i = 0; i <= NumberPacingPeriods * stimulusNumber - 1; i++)
688  {
689  if ( control < 1 )
690  {
691  if ( (t >= (returnStimulusTime[i] + stimulusStart) && t <= (returnStimulusTime[i] + stimulusStop + timeStep) ) )
692  {
693  splitting -> setAppliedCurrentFromFunction ( pacing );
694  std::cout << "stim_time " << t << std::endl;
695  control = control + 1;
696  }
697  else
698  {
699  splitting -> initializeAppliedCurrent();
700  }
701  }
702  }
703  k++;
704 
705  if (nbTimeStep == 1)
706  {
707  splitting->solveOneReactionStepFE();
708  (* (splitting->rhsPtrUnique() ) ) *= 0;
709  splitting->updateRhs();
710  splitting->solveOneDiffusionStepBE();
711  splitting->exportSolution (exporterSplitting, t);
712  }
713  else
714  {
715  * (previousPotential0Ptr) = * (splitting->globalSolution().at (0) );
716  splitting->solveOneReactionStepFE (2);
717  (* (splitting->rhsPtrUnique() ) ) *= 0;
718  splitting->updateRhs();
719  splitting->solveOneDiffusionStepBDF2 (previousPotential0Ptr);
720  splitting->solveOneReactionStepFE (2);
721  if (k % iter == 0)
722  {
723  splitting->exportSolution (exporterSplitting, t);
724  }
725  if (k % iterRestart == 0)
726  {
727  splitting->exportSolution (exporterSplittingRestart, t);
728  }
729  }
730  nbTimeStep++;
731 
732  // ECG : discrete laplacian of the solution
733  (*rhs_Laplacian) = (*systemMatrixL) * (* (splitting->globalSolution().at (0) ) );
734 
735  linearSolver2.setOperator ( systemMatrixM );
736  linearSolver2.setRightHandSide ( rhs_Laplacian );
737  linearSolver2.solve ( pseudoEcgVec_ptr );
738 
739  pseudoEcgVec = (*pseudoEcgVec_ptr) / ecgDistance;
740 
741  // // APD calculation
742  for (int i = 0; i <= sz - 1; i++)
743  {
744  if ( (* (splitting->globalSolution().at (0) ) ).isGlobalIDPresent (i) )
745  {
746 
747  if ( ( previouspotential[i] < threshold ) && ( (* (splitting->globalSolution().at (0) ) ) [i] >= threshold ) )
748  {
749  tact[i] = t - ( (-threshold + previouspotential[i]) / ( (* (splitting->globalSolution().at (0) ) ) [i] - previouspotential[i]) ) * timeStep;
750  }
751  else if ( ( previouspotential[i] >= threshold ) && ( (* (splitting->globalSolution().at (0) ) ) [i] < threshold ) )
752  {
753  trep = t - ( (-threshold + previouspotential[i]) / ( (* (splitting->globalSolution().at (0) ) ) [i] - previouspotential[i]) ) * timeStep;
754  delta_apd[i] = (trep - tact[i]) - apd[i];
755  apd[i] = trep - tact[i];
756  }
757 
758  // // Pseudo-ECG summation
759  pseudoEcgReal += pseudoEcgVec[i];
760  }
761  }
762  *APDptr = apd;
763  *DELTA_APDptr = delta_apd;
764 
765  MPI_Allreduce (&pseudoEcgReal, &Global_pseudoEcgReal, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); // rapporte a une variable connue de tous les procs
766 
767  if ( Comm->MyPID() == 0 )
768  {
769  output << Global_pseudoEcgReal << "\n";
770  }
771  }
772  }
773  splitting->exportSolution (exporterSplittingRestart, endTime);
774  exporterSplitting.closeFile();
775 
776  //********************************************//
777  // Saving Fiber direction to file //
778  //********************************************//
779  splitting -> exportFiberDirection();
780 
781  if ( Comm->MyPID() == 0 )
782  {
783  std::cout << "\nThank you for using ETA_MonodomainSolver.\nI hope to meet you again soon!\n All the best for your simulation :P\n " ;
784  }
785  MPI_Barrier (MPI_COMM_WORLD);
786  }
787  MPI_Finalize();
788  return ( EXIT_SUCCESS );
789 }
VectorEpetra - The Epetra Vector format Wrapper.
void assignFunction(bcBase_Type &base)
Assign the function to the base of the BCHandler.
Real Stimulus2(const Real &, const Real &x, const Real &y, const Real &z, const ID &)
Real Fibers(const Real &, const Real &, const Real &, const Real &z, const ID &i)
FESpace - Short description here please!
Definition: FESpace.hpp:78
int main(int argc, char **argv)
GetPot(const int argc_, char **argv_, const char *FieldSeparator=0x0)
Definition: GetPot.hpp:507
void importFromHDF5(std::string const &fileName, std::string const &matrixName="matrix")
Read a matrix from a HDF5 (.h5) file.
static void setPosition(const Real &xPosition, const Real &yPosition, const Real &zPosition)
Definition: Norm.hpp:54
IonicModel - This class implements an ionic model.
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
#define M_PI
Definition: winmath.h:20
Epetra_Import const & importer()
Getter for the Epetra_Import.
Definition: MapEpetra.cpp:394
uint32_type ID
IDs.
Definition: LifeV.hpp:194
std::shared_ptr< std::vector< Int > > M_isOnProc
double Real
Generic real data.
Definition: LifeV.hpp:175
Real PacingProtocol(const Real &, const Real &x, const Real &y, const Real &z, const ID &)
VectorEpetra & operator*=(const data_type &scalar)
Multiplication operator.