LifeV
lifev/electrophysiology/testsuite/test_pacing/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 using the pacing protocol
30 
31  In this test we use show an example of the use of the pacing protocols.
32 
33  @date 03 - 2014
34  @author Simone Rossi <simone.rossi@epfl.ch>
35 
36  @contributor
37  @mantainer Simone Rossi <simone.rossi@epfl.ch>
38  */
39 
40 // Tell the compiler to ignore specific kind of warnings:
41 #pragma GCC diagnostic ignored "-Wunused-variable"
42 #pragma GCC diagnostic ignored "-Wunused-parameter"
43 
44 #include <Epetra_ConfigDefs.h>
45 #ifdef EPETRA_MPI
46 #include <mpi.h>
47 #include <Epetra_MpiComm.h>
48 #else
49 #include <Epetra_SerialComm.h>
50 #endif
51 
52 //Tell the compiler to restore the warning previously silented
53 #pragma GCC diagnostic warning "-Wunused-variable"
54 #pragma GCC diagnostic warning "-Wunused-parameter"
55 
56 //We use this to transform the mesh from [0,1]x[0,1] to [0,5]x[0,5]
57 #include <lifev/core/mesh/MeshUtility.hpp>
58 
59 //We will use the ETAMonodomainSolver
60 #include <lifev/electrophysiology/solver/ElectroETAMonodomainSolver.hpp>
61 
62 //We will use the Aliev Panfilov model for simplicity
63 #include <lifev/electrophysiology/solver/IonicModels/IonicAlievPanfilov.hpp>
64 
65 //Include LifeV
66 #include <lifev/core/LifeV.hpp>
67 
68 //Include utilities for the pacing protocols
69 #include <lifev/electrophysiology/stimulus/StimulusPacingProtocol.hpp>
70 
71 //this is useful to save the out in a separate folder
72 #include <sys/stat.h>
73 
74 using namespace LifeV;
75 
76 //Norm of the solution in order to check if the test failed
77 #define solutionNorm 38.2973164904655
78 
79 //Forward declaration of the function defining the fiber direction.
80 //See the end of the file for the implementation
81 Real fiberDistribution ( const Real& /*t*/, const Real& /*x*/, const Real& y, const Real& z, const ID& id);
82 
83 // Test pacing
84 Int main ( Int argc, char** argv )
85 {
86 
87  //! Initializing Epetra communicator
88  MPI_Init (&argc, &argv);
89  std::shared_ptr<Epetra_Comm> Comm ( new Epetra_MpiComm (MPI_COMM_WORLD) );
90  if ( Comm->MyPID() == 0 )
91  {
92  std::cout << "% using MPI" << std::endl;
93  }
94 
95  //*********************************************//
96  // creating output folder
97  //*********************************************//
98  GetPot commandLine ( argc, argv );
99  std::string problemFolder = commandLine.follow ( "Output", 2, "-o", "--output" );
100  // Create the problem folder
101  if ( problemFolder.compare ("./") )
102  {
103  problemFolder += "/";
104 
105  if ( Comm->MyPID() == 0 )
106  {
107  mkdir ( problemFolder.c_str(), 0777 );
108  }
109  }
110 
111  //********************************************//
112  // Some typedefs //
113  //********************************************//
114 
115  typedef RegionMesh<LinearTetra> mesh_Type;
116 
117  typedef std::function < Real (const Real& /*t*/,
118  const Real & x,
119  const Real & y,
120  const Real& /*z*/,
121  const ID& /*i*/ ) > function_Type;
122 
123  typedef ElectroETAMonodomainSolver< mesh_Type, IonicAlievPanfilov > monodomainSolver_Type;
124  typedef std::shared_ptr< monodomainSolver_Type > monodomainSolverPtr_Type;
125 
126  typedef VectorEpetra vector_Type;
127  typedef std::shared_ptr<vector_Type> vectorPtr_Type;
128 
129  //********************************************//
130  // Import parameters from an xml list. Use //
131  // Teuchos to create a list from a given file //
132  // in the execution directory. //
133  //********************************************//
134 
135  if ( Comm->MyPID() == 0 )
136  {
137  std::cout << "Importing parameters list...";
138  }
139  Teuchos::ParameterList monodomainList = * ( Teuchos::getParametersFromXmlFile ( "MonodomainSolverParamList.xml" ) );
140  if ( Comm->MyPID() == 0 )
141  {
142  std::cout << " Done!" << std::endl;
143  }
144 
145  //********************************************//
146  // Creates a new model object representing the//
147  // model from Aliev and Panfilov 1996. The //
148  // model input are the parameters. Pass the //
149  // parameter list in the constructor //
150  //********************************************//
151  if ( Comm->MyPID() == 0 )
152  {
153  std::cout << "Building Constructor for Aliev Panfilov model ... ";
154  }
155  std::shared_ptr<IonicAlievPanfilov> model ( new IonicAlievPanfilov() );
156  if ( Comm->MyPID() == 0 )
157  {
158  std::cout << " Done!" << std::endl;
159  }
160 
161 
162  //********************************************//
163  // In the parameter list we need to specify //
164  // the mesh name and the mesh path. //
165  //********************************************//
166 
167  std::string meshName = monodomainList.get ("mesh_name", "lid16.mesh");
168  std::string meshPath = monodomainList.get ("mesh_path", "./");
169 
170  //********************************************//
171  // We need the GetPot datafile for to setup //
172  // the preconditioner. //
173  //********************************************//
174 
175  GetPot dataFile (argc, argv);
176 
177  //********************************************//
178  // We create the monodomain solver //
179  //********************************************//
180  if ( Comm->MyPID() == 0 )
181  {
182  std::cout << "Building Monodomain Solvers... ";
183  }
184 
185  monodomainSolverPtr_Type monodomain ( new monodomainSolver_Type ( meshName, meshPath, dataFile, model ) );
186  if ( Comm->MyPID() == 0 )
187  {
188  std::cout << " Splitting solver done... ";
189  }
190 
191  //********************************************//
192  // We transform the mesh to get a larger //
193  // domain. //
194  //********************************************//
195  std::vector<Real> scale (3, 1.0);
196  scale[2] = 5.0;
197  scale[1] = 5.0;
198  std::vector<Real> rotate (3, 0.0);
199  std::vector<Real> translate (3, 0.0);
200  MeshUtility::MeshTransformer<mesh_Type> transformer (* (monodomain -> localMeshPtr() ) );
201  transformer.transformMesh (scale, rotate, translate);
202 
203 
204  //********************************************//
205  // Initialize the solution //
206  //********************************************//
207  monodomain -> setInitialConditions();
208 
209  //********************************************//
210  // Setting up the monodomain solver parameters//
211  //********************************************//
212  monodomain -> setParameters ( monodomainList );
213 
214  //********************************************//
215  // fiber direction //
216  //********************************************//
217  if ( Comm->MyPID() == 0 )
218  {
219  std::cout << "\nSetting fibers: " ;
220  }
221  // This is used only to initialize the pointer in the solver
222  // could be replaced with a method "initialize fibers"
223  // where we just create the pointer to a vectorial vector.
224  // The method generates a default constant fiber direction (0,0,1).
225  // At least, in case of misuse, the fibers will not be zero
226  // and the signal may propagate.
227  monodomain -> setupFibers();
228  function_Type fibreFunction = &fiberDistribution;
229  ElectrophysiologyUtility::setFibersFromFunction (monodomain -> fiberPtr(), monodomain -> localMeshPtr(), fibreFunction);
230  ElectrophysiologyUtility::normalize (* (monodomain -> fiberPtr() ) );
231 
232  //********************************************//
233  // Set some noise in the fiber. //
234  // Set to false by default. //
235  //********************************************//
236  bool randomNoise = monodomainList.get ("noise", false);
237  if (randomNoise)
238  {
239  std::vector<bool> component (3, false);
240  component[0] = true;
241  Real magnitude = monodomainList.get ("noise_magnitude", 1e-3);
242  ElectrophysiologyUtility::addNoiseToFibers (* (monodomain -> fiberPtr() ), magnitude, component );
243  }
244  if ( Comm->MyPID() == 0 )
245  {
246  std::cout << "Done! \n" ;
247  }
248 
249  //********************************************//
250  // Saving Fiber direction to file //
251  //********************************************//
252  monodomain -> exportFiberDirection (problemFolder);
253 
254  //********************************************//
255  // Create the global matrix: mass + stiffness //
256  //********************************************//
257  if ( Comm->MyPID() == 0 )
258  {
259  std::cout << "\nSetup operators: " ;
260  }
261  monodomain -> setupLumpedMassMatrix();
262  monodomain -> setupStiffnessMatrix();
263  monodomain -> setupGlobalMatrix();
264  if ( Comm->MyPID() == 0 )
265  {
266  std::cout << "Done! \n" ;
267  }
268 
269  //********************************************//
270  // Creating exporters to save the solution //
271  //********************************************//
272  ExporterHDF5< RegionMesh <LinearTetra> > exporter;
273  monodomain -> setupExporter ( exporter, monodomainList.get ("OutputFile", "Solution"), problemFolder );
274  monodomain -> exportSolution ( exporter, 0);
275 
276  //********************************************//
277  // Solving the system //
278  //********************************************//
279  if ( Comm->MyPID() == 0 )
280  {
281  std::cout << "\nstart solving: " ;
282  }
283 
284  Real dt = monodomain -> timeStep();
285  //Uncomment for proper use
286  Real TF = monodomainList.get ("endTime", 48.0);
287  Int iter = monodomainList.get ("saveStep", 1.0) / dt;
288 
289 
290  //********************************************//
291  // Define the pacing protocol //
292  //********************************************//
293  StimulusPacingProtocol pacing;
294 
295  //********************************************//
296  // Import parameters for the pacing protocol //
297  //********************************************//
298 
299  if ( Comm->MyPID() == 0 )
300  {
301  std::cout << "Importing pacing protocol parameters ...";
302  }
303  std::string pacingListFileName = monodomainList.get ("pacing_parameter_list_filename", "PacingParameters.xml");
304  Teuchos::ParameterList pacingList = * ( Teuchos::getParametersFromXmlFile ( pacingListFileName ) );
305  if ( Comm->MyPID() == 0 )
306  {
307  std::cout << " Done!" << std::endl;
308  }
309 
310  pacing.setParameters (pacingList);
311  pacing.setTimeStep ( monodomain -> timeStep() );
312 
313  //********************************************//
314  // Loop over time solving with L-ICI //
315  //********************************************//
316  int loop = 0;
317  for (Real t = monodomain -> initialTime(); t < TF;)
318  {
319  //********************************************//
320  // Set the applied current from the pacing //
321  // protocol //
322  //********************************************//
323  monodomain -> setAppliedCurrentFromElectroStimulus ( pacing, t);
324  loop++;
325  t += dt;
326 
327  //********************************************//
328  // Solve the monodomain equations. //
329  //********************************************//
330 
331  monodomain -> solveOneStepGatingVariablesFE();
332  monodomain -> solveOneICIStep();
333 
334  //********************************************//
335  // Exporting the solution. //
336  //********************************************//
337  if (loop % iter == 0 )
338  {
339  if ( Comm->MyPID() == 0 )
340  {
341  std::cout << "\ntime = " << t;
342  }
343  exporter.postProcess (t);
344  }
345  }
346 
347  //********************************************//
348  // Close the exporter //
349  //********************************************//
350 
351  exporter.closeFile();
352 
353 
354  //********************************************//
355  // Check if the test failed //
356  //********************************************//
357  Real newSolutionNorm = monodomain -> potentialPtr() -> norm2();
358 
359  monodomain.reset();
360  MPI_Barrier (MPI_COMM_WORLD);
361  MPI_Finalize();
362 
363 
364  Real err = std::abs (newSolutionNorm - solutionNorm) / std::abs (solutionNorm);
365  if ( err > 1e-8 )
366  {
367  std::cout << "\nTest Failed: " << err << "\n" << "\nSolution Norm: " << newSolutionNorm << "\n";
368  return EXIT_FAILURE; // Norm of solution did not match
369  }
370  else
371  {
372  return EXIT_SUCCESS;
373  }
374 }
375 
376 #undef solutionNorm
377 
378 //Definition of the fiber direction
379 Real fiberDistribution ( const Real& /*t*/, const Real& /*x*/, const Real& y, const Real& z, const ID& id)
380 {
381  Real y0 = 2.5;
382  Real z0 = 2.5;
383  Real r = std::sqrt ( (y - y0) * (y - y0) + (z - z0) * (z - z0) );
384 
385  switch ( id )
386  {
387  case 0:
388  return 0.0;
389  case 1:
390  if (r > 1e-16)
391  {
392  return (z - z0) / r;
393  }
394  else
395  {
396  return 0.0;
397  }
398  case 2:
399  if (r > 1e-16)
400  {
401  return (y0 - y) / r;
402  }
403  else
404  {
405  return 1.0;
406  }
407  default:
408  return 0.0;
409  }
410 }
VectorEpetra - The Epetra Vector format Wrapper.
GetPot(const int argc_, char **argv_, const char *FieldSeparator=0x0)
Definition: GetPot.hpp:507
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
uint32_type ID
IDs.
Definition: LifeV.hpp:194
Real fiberDistribution(const Real &, const Real &, const Real &y, const Real &z, const ID &id)
double Real
Generic real data.
Definition: LifeV.hpp:175
int main(int argc, char **argv)
const std::string follow(const char *Default, unsigned No, const char *Option,...)
Definition: GetPot.hpp:1510