LifeV
HeartIonicSolver.hpp
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 Class for choosing and solving ionic models in electrophysiology. Mitchel-Schaeffer, Rogers-McCulloch, Luo-Rudy I
30 
31  @date 11-2007
32  @author Lucia Mirabella <lucia.mirabella@mail.polimi.it> and Mauro Perego <mauro.perego@polimi.it>
33 
34  @contributors J.Castelneau (INRIA), Ricardo Ruiz-Baier <ricardo.ruiz@epfl.ch>
35  @mantainer Lucia Mirabella <lucia.mirabella@mail.polimi.it>
36  @last update 11-2010
37  */
38 
39 #ifndef _IONICSOLVER_H_
40 #define _IONICSOLVER_H_
41 
42 #include <lifev/core/array/MatrixElemental.hpp>
43 #include <lifev/core/array/VectorElemental.hpp>
44 #include <lifev/core/fem/Assembly.hpp>
45 #include <lifev/core/fem/AssemblyElemental.hpp>
46 #include <lifev/core/fem/BCManage.hpp>
47 #include <lifev/core/algorithm/SolverAztecOO.hpp>
48 #include <lifev/core/array/MapEpetra.hpp>
49 #include <lifev/core/array/MatrixEpetra.hpp>
50 #include <lifev/core/array/VectorEpetra.hpp>
51 #include <lifev/core/fem/SobolevNorms.hpp>
52 #include <lifev/core/fem/GeometricMap.hpp>
53 #include <lifev/heart/solver/HeartIonicData.hpp>
54 #include <lifev/core/util/LifeChrono.hpp>
55 #include <boost/shared_ptr.hpp>
56 #include <lifev/core/fem/FESpace.hpp>
57 #include <lifev/core/fem/TimeAdvanceBDF.hpp>
58 
59 namespace LifeV
60 {
61 //! IonicSolver - This class implements a ionic model solver.
62 
63 
64 template < typename Mesh,
65  typename SolverType = LifeV::SolverAztecOO >
67 {
68 
69 public:
70  //! @name Type definitions
71  //@{
72 
74 
75  typedef Real ( *function_Type ) ( const Real&,
76  const Real&,
77  const Real&,
78  const Real&,
79  const ID& );
80 
81  typedef std::function < Real (const markerID_Type& ref,
82  const Real& x,
83  const Real& y,
84  const Real& z,
86 
87  typedef Mesh mesh_Type;
88 
89  typedef typename SolverType::matrix_type matrix_Type;
90  typedef typename SolverType::vector_type vector_Type;
91 
92  typedef typename SolverType::prec_raw_type precRaw_Type;
93  typedef typename SolverType::prec_type prec_Type;
94 
95  //@}
96 
97 
98 
99  //! @name Constructors & Destructor
100  //@{
101 
102  //! Constructor
103  /*!
104  * @param dataType
105  * @param mesh
106  * @param recovery FE space
107  * @param Epetra communicator
108  */
109  HeartIonicSolver ( const data_Type& dataType,
110  const Mesh& mesh,
111  FESpace<Mesh, MapEpetra>& uFEspace,
112  Epetra_Comm& comm );
113 
114  //! Destructor
115  virtual ~HeartIonicSolver() {}
116 
117  //@}
118 
119  //! @name Methods
120  //@{
121 
122 
123  //! Returns the recovery variable FE space
125  {
126  return M_uFESpace;
127  }
128 
129  //! Return maps
131  {
132  return *M_localMap.map (Repeated);
133  }
134 
135  MapEpetra const& getMap() const
136  {
137  return M_localMap;
138  }
139 
140  virtual void updateRepeated( ) = 0;
141 
142  //! Update the ionic model elvecs
143  virtual void updateElementSolution ( UInt eleIDw ) = 0;
144 
145  //! Solves the ionic model
146  virtual void solveIonicModel ( const vector_Type& u,
147  const Real timeStep ) = 0;
148 
149  //! Computes the term -1/ \Cm u^n (G (1-u^n/vp) (1-u^n/v_th) + eta_1 v^{n+1})
150  //! for the PDE righthand side
151  virtual void computeIonicCurrent ( Real Capacitance,
152  VectorElemental& elvec,
153  VectorElemental& elvec_u,
154  FESpace<Mesh, MapEpetra>& uFESpace ) = 0;
155 
156  //! Initialize
157  virtual void initialize( ) = 0;
158 
160 
161  const Mesh& M_mesh;
162 
163  // FE space
165 
166  //! MPI communicator
168 
170 
171  //! Map
173 
174  //! Boolean that indicates if output is sent to cout
175  bool M_verbose;
176 
177  //@}
178 
179 protected:
180 
182  {
183  return M_uFESpace.dim();
184  }
185 
186 }; // class IonicSolver
187 
188 
189 //
190 // IMPLEMENTATION
191 //
192 
193 //! Constructor
194 template<typename Mesh, typename SolverType>
195 HeartIonicSolver<Mesh, SolverType>::
196 HeartIonicSolver ( const data_Type& dataType,
197  const Mesh& mesh,
198  FESpace<Mesh, MapEpetra>& uFEspace,
199  Epetra_Comm& comm ) :
200  M_data ( dataType ),
201  M_mesh ( mesh ),
202  M_uFESpace ( uFEspace ),
203  M_comm ( &comm ),
204  M_me ( M_comm->MyPID() ),
205  M_localMap ( M_uFESpace.map() ),
206  M_verbose ( M_me == 0)
207 {
208 }
209 
210 template < typename Mesh,
211  typename SolverType = LifeV::SolverAztecOO >
212 class MitchellSchaeffer : public virtual HeartIonicSolver<Mesh, SolverType>
213 {
214 public:
215  typedef typename HeartIonicSolver<Mesh, SolverType>::data_Type data_Type;
216  typedef typename HeartIonicSolver<Mesh, SolverType>::vector_Type vector_Type;
217  typedef typename HeartIonicSolver<Mesh, SolverType>::function_Type function_Type;
218  typedef typename HeartIonicSolver<Mesh, SolverType>::functorTauClose_Type functorTauClose_Type;
219 
220  MitchellSchaeffer ( const data_Type& dataType,
221  const Mesh& mesh,
222  FESpace<Mesh, MapEpetra>& uFEspace,
223  Epetra_Comm& comm );
224 
225  virtual ~MitchellSchaeffer();
226 
227  void updateRepeated( );
228 
229  void updateElementSolution ( UInt eleID );
230 
231  void solveIonicModel ( const vector_Type& u, const Real timeStep );
232 
233  void computeIonicCurrent ( Real Capacitance,
234  VectorElemental& elvec,
235  VectorElemental& elvec_u,
236  FESpace<Mesh, MapEpetra>& uFESpace );
237 
239  {
240  return M_solutionGatingW;
241  }
242 
243  void initialize( );
244 
246 
247  Real functorTauClose (const markerID_Type& ref,
248  const Real& x,
249  const Real& y,
250  const Real& z,
251  const ID& i) const;
252 
253 protected:
254 
255  //! Global solution _w
258  VectorElemental M_elvec;
262 
263 private:
264 };
265 
266 
267 //
268 // IMPLEMENTATION
269 //
270 
271 //! Constructor
272 template<typename Mesh, typename SolverType>
273 MitchellSchaeffer<Mesh, SolverType>::
274 MitchellSchaeffer ( const data_Type& dataType,
275  const Mesh& mesh,
276  FESpace<Mesh, MapEpetra>& uFEspace,
277  Epetra_Comm& comm ) :
279  M_solutionGatingW ( HeartIonicSolver<Mesh, SolverType>::M_localMap ),
282  M_BDForder ( HeartIonicSolver<Mesh, SolverType>::M_data.MSBDForder() ),
283  M_BDFW( )
284 {
285  M_BDFW.setup ( M_BDForder );
286 }
287 
288 template<typename Mesh, typename SolverType>
289 MitchellSchaeffer<Mesh, SolverType>::
291 {
292 }
293 
294 template<typename Mesh, typename SolverType>
295 void MitchellSchaeffer<Mesh, SolverType>::updateRepeated( )
296 {
298 }
299 
300 template<typename Mesh, typename SolverType>
301 void MitchellSchaeffer<Mesh, SolverType>::updateElementSolution ( UInt eleID )
302 {
303  M_elvec.zero();
304  UInt ig;
305  //! Filling local elvec_w with recovery variable values in the nodes
306  for ( UInt iNode = 0 ; iNode < HeartIonicSolver<Mesh, SolverType>::M_uFESpace.fe().nbFEDof() ; iNode++ )
307  {
308  ig = HeartIonicSolver<Mesh, SolverType>::M_uFESpace.dof().localToGlobalMap ( eleID, iNode );
309  M_elvec.vec() [ iNode ] = M_solutionGatingWRepeated[ig];
310  }
311 }
312 
313 template<typename Mesh, typename SolverType>
315 {
316  M_tauClose = fct;
317 }
318 
319 template<typename Mesh, typename SolverType>
320 Real MitchellSchaeffer<Mesh, SolverType>::functorTauClose (const markerID_Type& ref,
321  const Real& x,
322  const Real& y,
323  const Real& z, const ID& i) const
324 {
325  return M_tauClose (ref, x, y, z, i);
326 }
327 
328 template<typename Mesh, typename SolverType>
329 void MitchellSchaeffer<Mesh, SolverType>::solveIonicModel ( const vector_Type& u, const Real timeStep )
330 {
331  //! Solving :
332  //! ((v_max-v_min)^{-2} - w )/tau_open if u < vcrit
333  //! dw/dt ={
334  //! -w/tau_close if u > vcrit
335 
336  Real aux1 = 1.0 / (M_BDFW.coefficientFirstDerivative (0) / timeStep +
337  1.0 / this->M_data.MSTauOpen() );
338  Real aux = 1.0 / ( (this->M_data.MSPotentialMaximum() -
339  this->M_data.MSPotentialMinimum() ) *
340  (this->M_data.MSPotentialMaximum() -
341  this->M_data.MSPotentialMinimum() ) *
342  this->M_data.MSTauOpen() );
343  Real aux2 = 1.0 / (M_BDFW.coefficientFirstDerivative (0) / timeStep +
344  1.0 / this->M_data.MSTauClose() );
345 
346  M_BDFW.updateRHSContribution (timeStep);
347  vector_Type M_time_der = M_BDFW.rhsContributionFirstDerivative();
348 
349  HeartIonicSolver<Mesh, SolverType>::M_comm->Barrier();
350  UInt ID;
351  for ( Int i = 0 ; i < u.epetraVector().MyLength() ; ++i )
352  {
353  Int ig = u.blockMap().MyGlobalElements() [i];
354  ID = ig;
355  /*ref = this->M_mesh->point(ig).markerID();
356  x = this->M_mesh->point(ig).x();
357  y = this->M_mesh->point(ig).y();
358  z = this->M_mesh->point(ig).z();*/
359  if (u[ig] < this->M_data.MSCriticalPotential() )
360  {
361  M_solutionGatingW[ig] = aux1 * (aux + M_time_der[ig]);
362  }
363  else if (this->M_data.MSHasHeterogeneousTauClose() )
364  M_solutionGatingW[ig] = (1.0 / (M_BDFW.coefficientFirstDerivative (0) / timeStep +
365  1.0/*fct_Tau_Close(ref,x,y,z,ID)*/) ) *
366  M_time_der[ig];//aux2 * M_time_der[ig];
367  else
368  {
369  M_solutionGatingW[ig] = aux2 * M_time_der[ig];
370  }
371  }
372  M_BDFW.shiftRight (M_solutionGatingW);
373 
374  HeartIonicSolver<Mesh, SolverType>::M_comm->Barrier();
375 }
376 
377 template<typename Mesh, typename SolverType>
378 void MitchellSchaeffer<Mesh, SolverType>::computeIonicCurrent ( Real,
379  VectorElemental& elvec,
380  VectorElemental& elvec_u,
381  FESpace<Mesh, MapEpetra>& uFESpace )
382 {
383  for ( UInt i = 0; i < uFESpace.fe().nbFEDof(); i++ )
384  {
385  elvec ( i ) = this->M_data.MSReactionAmplitude() *
386  ( ( (M_elvec ( i ) / this->M_data.MSTauIn() ) *
387  (elvec_u ( i ) - this->M_data.MSPotentialMinimum() ) *
388  (elvec_u ( i ) - this->M_data.MSPotentialMinimum() ) *
389  (this->M_data.MSPotentialMaximum() - elvec_u ( i ) ) /
390  (this->M_data.MSPotentialMaximum() - this->M_data.MSPotentialMinimum() ) ) -
391  ( ( elvec_u ( i ) - this->M_data.MSPotentialMinimum() ) /
392  ( this->M_data.MSTauOut() * (this->M_data.MSPotentialMaximum() -
393  this->M_data.MSPotentialMinimum() ) ) ) ) ;
394  }
395 }
396 
397 template<typename Mesh, typename SolverType>
398 void MitchellSchaeffer<Mesh, SolverType>::
400 {
401  M_solutionGatingW.epetraVector().PutScalar (1.0 /
402  ( (this->M_data.MSPotentialMaximum() -
403  this->M_data.MSPotentialMinimum() ) *
404  (this->M_data.MSPotentialMaximum() -
405  this->M_data.MSPotentialMinimum() ) ) );
406  M_BDFW.setInitialCondition (M_solutionGatingW);
407  M_BDFW.showMe();
408 }
409 
410 template < typename Mesh,
411  typename SolverType = LifeV::SolverAztecOO >
412 class RogersMcCulloch : public virtual HeartIonicSolver<Mesh, SolverType>
413 {
414 public:
415  typedef typename HeartIonicSolver<Mesh, SolverType>::data_Type data_Type;
416  typedef typename HeartIonicSolver<Mesh, SolverType>::vector_Type vector_Type;
417  typedef typename HeartIonicSolver<Mesh, SolverType>::function_Type function_Type;
418 
419  RogersMcCulloch ( const data_Type& dataType,
420  const Mesh& mesh,
421  FESpace<Mesh, MapEpetra>& uFEspace,
422  Epetra_Comm& comm );
423  virtual ~RogersMcCulloch();
424 
425  void updateRepeated( );
426 
427  void updateElementSolution ( UInt eleID );
428 
429  void solveIonicModel ( const vector_Type& u, const Real timeStep );
430 
431  void computeIonicCurrent ( Real Capacitance,
432  VectorElemental& elvec,
433  VectorElemental& elvec_u,
434  FESpace<Mesh, MapEpetra>& uFESpace );
435 
437  {
438  return M_solutionGatingW;
439  }
440 
441  void initialize( );
442 
443 protected:
444 
445  //! Global solution _w
448  VectorElemental M_elvec;
449 private:
450 };
451 
452 
453 //
454 // IMPLEMENTATION
455 //
456 
457 //! Constructor
458 template<typename Mesh, typename SolverType>
459 RogersMcCulloch<Mesh, SolverType>::
460 RogersMcCulloch ( const data_Type& dataType,
461  const Mesh& mesh,
462  FESpace<Mesh, MapEpetra>& uFEspace,
463  Epetra_Comm& comm ) :
465  M_solutionGatingW ( HeartIonicSolver<Mesh, SolverType>::M_localMap ),
468 {
469 }
470 
471 template<typename Mesh, typename SolverType>
472 RogersMcCulloch<Mesh, SolverType>::
474 {
475 }
476 
477 template<typename Mesh, typename SolverType>
478 void RogersMcCulloch<Mesh, SolverType>::updateRepeated( )
479 {
481 }
482 
483 template<typename Mesh, typename SolverType>
484 void RogersMcCulloch<Mesh, SolverType>::updateElementSolution ( UInt eleID )
485 {
486  M_elvec.zero();
487  UInt ig;
488  for ( UInt iNode = 0 ;
489  iNode < HeartIonicSolver<Mesh, SolverType>::M_uFESpace.fe().nbFEDof() ; iNode++ )
490  {
491  ig = HeartIonicSolver<Mesh, SolverType>::M_uFESpace.dof().localToGlobalMap ( eleID, iNode );
492  M_elvec.vec() [ iNode ] = M_solutionGatingWRepeated[ig];
493  }
494 }
495 
496 template<typename Mesh, typename SolverType>
497 void RogersMcCulloch<Mesh, SolverType>::solveIonicModel ( const vector_Type& u, const Real timeStep )
498 {
499  //! Solving dw/dt= b/(A*T) (u - u0 - A d w)
500  Real G = this->M_data.RMCParameterB() / this->M_data.RMCPotentialAmplitude() / this->M_data.RMCTimeUnit();
501 
502  Real alpha = 1 / timeStep + G * this -> M_data.RMCPotentialAmplitude() * this -> M_data.RMCParameterD() ;
503 
504  HeartIonicSolver<Mesh, SolverType>::M_comm->Barrier();
505 
506  M_solutionGatingW *= 1 / timeStep;
507  vector_Type temp (u);
508  temp.epetraVector().PutScalar ( G * this -> M_data.RMCRestPotential() );
509  M_solutionGatingW += G * u;
510  M_solutionGatingW -= temp;
511  M_solutionGatingW *= 1 / alpha;
512  M_solutionGatingW.globalAssemble();
513  HeartIonicSolver<Mesh, SolverType>::M_comm->Barrier();
514 
515 }
516 
517 template<typename Mesh, typename SolverType>
518 void RogersMcCulloch<Mesh, SolverType>::computeIonicCurrent ( Real Capacitance,
519  VectorElemental& elvec,
520  VectorElemental& elvec_u,
521  FESpace<Mesh, MapEpetra>& uFESpace )
522 {
523  Real u_ig, w_ig;
524 
525  Real G1 = this->M_data.RMCParameterC1() / this->M_data.RMCTimeUnit() / std::pow (this->M_data.RMCPotentialAmplitude(), 2.0);
526  Real G2 = this->M_data.RMCParameterC2() / this->M_data.RMCTimeUnit();
527 
528  for ( UInt ig = 0; ig < uFESpace.fe().nbQuadPt(); ig++ )
529  {
530  u_ig = w_ig = 0.;
531  for ( UInt i = 0; i < uFESpace.fe().nbFEDof(); i++ )
532  {
533  u_ig += elvec_u ( i ) * uFESpace.fe().phi ( i, ig );
534  }
535  for ( UInt i = 0; i < uFESpace.fe().nbFEDof(); i++ )
536  {
537  w_ig += M_elvec ( i ) * uFESpace.fe().phi ( i, ig );
538  }
539 
540  for ( UInt i = 0; i < uFESpace.fe().nbFEDof(); i++ )
541  {
542  elvec ( i ) -= Capacitance * ( G1 * ( u_ig - this -> M_data.RMCRestPotential() ) *
543  (u_ig - this->M_data.RMCRestPotential() -
544  this->M_data.RMCParameterA() * this->M_data.RMCPotentialAmplitude() ) *
545  (u_ig - this->M_data.RMCRestPotential() -
546  this->M_data.RMCPotentialAmplitude() ) + G2 *
547  (u_ig - this->M_data.RMCRestPotential() ) * w_ig) *
548  uFESpace.fe().phi ( i, ig ) * uFESpace.fe().weightDet ( ig );
549  }
550  }
551 }
552 
553 template<typename Mesh, typename SolverType>
554 void RogersMcCulloch<Mesh, SolverType>::
556 {
557  M_solutionGatingW.epetraVector().PutScalar (0.);
558 }
559 
560 template < typename Mesh,
561  typename SolverType = LifeV::SolverAztecOO >
562 class LuoRudy : public virtual HeartIonicSolver<Mesh, SolverType>
563 {
564 public:
565  typedef typename HeartIonicSolver<Mesh, SolverType>::data_Type data_Type;
566  typedef typename HeartIonicSolver<Mesh, SolverType>::vector_Type vector_Type;
567  typedef typename HeartIonicSolver<Mesh, SolverType>::function_Type function_Type;
568 
569  LuoRudy ( const data_Type& dataType,
570  const Mesh& mesh,
571  FESpace<Mesh, MapEpetra>& uFEspace,
572  Epetra_Comm& comm );
573 
574  virtual ~LuoRudy() {}
575 
576  void updateRepeated( );
577 
578  void updateElementSolution ( UInt eleID);
579 
580  void computeODECoefficients ( const Real& u_ig );
581 
582  void solveIonicModel ( const vector_Type& u, const Real timeStep );
583 
584  void computeIonicCurrent ( Real Capacitance,
585  VectorElemental& elvec,
586  VectorElemental& elvec_u,
587  FESpace<Mesh, MapEpetra>& uFESpace );
588 
589  void initialize ( );
590 
591  //! Returns the local solution vector for each field
593  {
594  return M_solutionGatingH;
595  }
596 
598  {
599  return M_solutionGatingJ;
600  }
601 
603  {
604  return M_solutionGatingM;
605  }
606 
608  {
609  return M_solutionGatingD;
610  }
611 
613  {
614  return M_solutionGatingF;
615  }
616 
618  {
619  return M_solutionGatingX;
620  }
621 
623  {
624  return M_solutionGatingCa;
625  }
626 
631  M_Xinf, M_tauX;
632 
633  //fast sodium current
635  //slow inward current
637  //time dependent potassium current
639  //time independent potassium current
641  //plateau potassium current
643  //background current
645  //Total time independent potassium current
647 
661 
662 protected:
663  //! Global solution h
665  //! Global solution j
667  //! Global solution m
669  //! Global solution d
671  //! Global solution f
673  //! Global solution X
675  //! Global solution Ca_i
677 
679 
681 
682  VectorElemental M_elemVecIonicCurrent;
683 
684 private:
685 };
686 
687 
688 //
689 // IMPLEMENTATION
690 //
691 
692 
693 //! Constructor
694 template<typename Mesh, typename SolverType>
695 LuoRudy<Mesh, SolverType>::
696 LuoRudy ( const data_Type& dataType,
697  const Mesh& mesh,
698  FESpace<Mesh, MapEpetra>& uFEspace,
699  Epetra_Comm& comm ) :
701  M_K0 (5.4),
702  M_Ki (145.),
703  M_Na0 (140.),
704  M_Nai (18.),
705  M_R (8.314472), //% Joules/(Kelvin*mole)
706  M_temperature (307.7532), //%kelvins
707  M_F (96485.33838), //% coulumbs/mole
708  M_permeabilityRatio (0.01833), //% Na/K permeability ratio
709  M_c (1.), //% membrane capacitance set as 1 mui-F/cm^2
710  M_Ena (1000. * (M_R* M_temperature / M_F ) * std::log (M_Na0 / M_Nai) ),
711  M_Gk (0.282 * std::sqrt (M_K0 / 5.4) ),
712  M_Ek (1000. * (M_R* M_temperature / M_F) * std::log ( (M_K0 + M_permeabilityRatio* M_Na0)
713  / (M_Ki + M_permeabilityRatio* M_Nai) ) ),
714  M_Gk1 (0.6047 * std::sqrt (M_K0 / 5.4) ),
715  M_Ek1 (1000.* (M_R* M_temperature / M_F) * std::log (M_K0 / M_Ki) ),
716  M_Ekp (M_Ek1),
717  M_vectorExponentialh (HeartIonicSolver<Mesh, SolverType>::M_localMap),
718  M_vectorExponentialj (HeartIonicSolver<Mesh, SolverType>::M_localMap),
719  M_vectorExponentialm (HeartIonicSolver<Mesh, SolverType>::M_localMap),
720  M_vectorExponentiald (HeartIonicSolver<Mesh, SolverType>::M_localMap),
721  M_vectorExponentialf (HeartIonicSolver<Mesh, SolverType>::M_localMap),
722  M_vectorExponentialX (HeartIonicSolver<Mesh, SolverType>::M_localMap),
723  M_vectorInfimumh (HeartIonicSolver<Mesh, SolverType>::M_localMap),
724  M_vectorInfimumj (HeartIonicSolver<Mesh, SolverType>::M_localMap),
725  M_vectorInfimumm (HeartIonicSolver<Mesh, SolverType>::M_localMap),
726  M_vectorInfimumd (HeartIonicSolver<Mesh, SolverType>::M_localMap),
727  M_vectorInfimumf (HeartIonicSolver<Mesh, SolverType>::M_localMap),
728  M_vectorInfimumX (HeartIonicSolver<Mesh, SolverType>::M_localMap),
729  M_vectorIonicChange (HeartIonicSolver<Mesh, SolverType>::M_localMap),
730  M_solutionGatingH ( HeartIonicSolver<Mesh, SolverType>::M_localMap ),
731  M_solutionGatingJ ( HeartIonicSolver<Mesh, SolverType>::M_localMap ),
732  M_solutionGatingM ( HeartIonicSolver<Mesh, SolverType>::M_localMap ),
733  M_solutionGatingD ( HeartIonicSolver<Mesh, SolverType>::M_localMap ),
734  M_solutionGatingF ( HeartIonicSolver<Mesh, SolverType>::M_localMap ),
735  M_solutionGatingX ( HeartIonicSolver<Mesh, SolverType>::M_localMap ),
736  M_solutionGatingCa ( HeartIonicSolver<Mesh, SolverType>::M_localMap ),
737  M_ionicCurrent ( HeartIonicSolver<Mesh, SolverType>::M_localMap ),
740 {
741 }
742 
743 template<typename Mesh, typename SolverType>
744 void LuoRudy<Mesh, SolverType>::updateRepeated( )
745 {
746 
748 }
749 
750 template<typename Mesh, typename SolverType>
751 void LuoRudy<Mesh, SolverType>::updateElementSolution ( UInt eleID)
752 {
753  M_elemVecIonicCurrent.zero();
754  UInt ig;
755  //! Filling local elvec with recovery variable values in the nodes
756  for ( UInt iNode = 0 ; iNode < HeartIonicSolver<Mesh, SolverType>::M_uFESpace.fe().nbFEDof() ; iNode++ )
757  {
758  ig = HeartIonicSolver<Mesh, SolverType>::M_uFESpace.dof().localToGlobalMap ( eleID, iNode );
759  M_elemVecIonicCurrent.vec() [ iNode ] = M_ionicCurrentRepeated[ig];
760  }
761 
762 }
763 
764 
765 template<typename Mesh, typename SolverType>
766 void LuoRudy<Mesh, SolverType>::solveIonicModel ( const vector_Type& u, const Real timeStep )
767 {
768  //! Solving dw/dt=eta2 (u/vp - eta3 w)
769  LifeChrono chronoionmodelsolve;
770  chronoionmodelsolve.start();
771  HeartIonicSolver<Mesh, SolverType>::M_comm->Barrier();
772 
773  for ( Int i = 0 ; i < u.epetraVector().MyLength() ; i++ )
774  {
775  Int ig = u.blockMap().MyGlobalElements() [i];
776  Real u_ig = u[ig];
778  M_Esi = 7.7 - 13.0287 * std::log (M_solutionGatingCa[ig]);
779  //fast sodium current
781  //slow inward current
782  M_Islow = 0.09 * M_solutionGatingD[ig] * M_solutionGatingF[ig] * (u_ig - M_Esi);
783  //change in ioniq concentration
784  M_vectorIonicChange.epetraVector().ReplaceGlobalValue (ig,
785  0,
786  -1e-4 * M_Islow + 0.07 * (1e-4 - M_solutionGatingCa[ig]) );
787  //time dependent potassium current
788  M_Ik = M_Gk * M_solutionGatingX[ig] * M_xii * (u_ig - M_Ek);
789  //time independent potassium current
790  M_Ik1 = M_Gk1 * M_K1inf * (u_ig - M_Ek1);
791  //plateau potassium current
792  M_Ikp = 0.0183 * M_Kp * (u_ig - M_Ekp);
793  //background current
794  M_Iback = 0.03921 * (u_ig + 59.87);
795  //Total time independent potassium current
796  M_Ik1t = M_Ik1 + M_Ikp + M_Iback;
797  // adding up the six ionic currents
798  M_ionicCurrent.epetraVector().ReplaceGlobalValue (ig,
799  0,
800  M_Ina + M_Islow + M_Ik + M_Ik1t);
801  M_vectorExponentialh.epetraVector().ReplaceGlobalValue (ig,
802  0,
803  std::exp (-timeStep / M_tauh) );
804  M_vectorExponentialj.epetraVector().ReplaceGlobalValue (ig,
805  0,
806  std::exp (-timeStep / M_tauj) );
807  M_vectorExponentialm.epetraVector().ReplaceGlobalValue (ig,
808  0,
809  std::exp (-timeStep / M_taum) );
810  M_vectorExponentiald.epetraVector().ReplaceGlobalValue (ig,
811  0,
812  std::exp (-timeStep / M_taud) );
813  M_vectorExponentialf.epetraVector().ReplaceGlobalValue (ig,
814  0,
815  std::exp (-timeStep / M_tauf) );
816  M_vectorExponentialX.epetraVector().ReplaceGlobalValue (ig,
817  0,
818  std::exp (-timeStep / M_tauX) );
819  M_vectorInfimumh.epetraVector().ReplaceGlobalValue (ig,
820  0,
821  M_hinf);
822  M_vectorInfimumj.epetraVector().ReplaceGlobalValue (ig,
823  0,
824  M_jinf);
825  M_vectorInfimumm.epetraVector().ReplaceGlobalValue (ig,
826  0,
827  M_minf);
828  M_vectorInfimumd.epetraVector().ReplaceGlobalValue (ig,
829  0,
830  M_dinf);
831  M_vectorInfimumf.epetraVector().ReplaceGlobalValue (ig,
832  0,
833  M_finf);
834  M_vectorInfimumX.epetraVector().ReplaceGlobalValue (ig,
835  0,
836  M_Xinf);
837  }
838  M_vectorExponentialh.globalAssemble();
839  M_vectorExponentialj.globalAssemble();
840  M_vectorExponentialm.globalAssemble();
841  M_vectorExponentiald.globalAssemble();
842  M_vectorExponentialf.globalAssemble();
843  M_vectorExponentialX.globalAssemble();
844  M_vectorInfimumh.globalAssemble();
845  M_vectorInfimumj.globalAssemble();
846  M_vectorInfimumm.globalAssemble();
847  M_vectorInfimumd.globalAssemble();
848  M_vectorInfimumf.globalAssemble();
849  M_vectorInfimumX.globalAssemble();
850  M_ionicCurrent.globalAssemble();
851  M_vectorIonicChange.globalAssemble();
852 
854  M_solutionGatingH.epetraVector().Multiply (1.,
855  M_solutionGatingH.epetraVector(),
856  M_vectorExponentialh.epetraVector(),
857  0.);
860 
861  M_solutionGatingJ.epetraVector().Multiply (1.,
862  M_solutionGatingJ.epetraVector(),
863  M_vectorExponentialj.epetraVector(),
864  0.);
867  M_solutionGatingM.epetraVector().Multiply (1.,
868  M_solutionGatingM.epetraVector(),
869  M_vectorExponentialm.epetraVector(),
870  0.);
873 
874  M_solutionGatingD.epetraVector().Multiply (1.,
875  M_solutionGatingD.epetraVector(),
876  M_vectorExponentiald.epetraVector(),
877  0.);
880 
881  M_solutionGatingF.epetraVector().Multiply (1.,
882  M_solutionGatingF.epetraVector(),
883  M_vectorExponentialf.epetraVector(),
884  0.);
887 
888  M_solutionGatingX.epetraVector().Multiply (1.,
889  M_solutionGatingX.epetraVector(),
890  M_vectorExponentialX.epetraVector(),
891  0.);
894 
895  M_solutionGatingH.globalAssemble();
896  M_solutionGatingJ.globalAssemble();
897  M_solutionGatingM.globalAssemble();
898  M_solutionGatingD.globalAssemble();
899  M_solutionGatingF.globalAssemble();
900  M_solutionGatingX.globalAssemble();
901  M_solutionGatingCa.globalAssemble();
902 
903  HeartIonicSolver<Mesh, SolverType>::M_comm->Barrier();
904 
905  chronoionmodelsolve.stop();
906  if (HeartIonicSolver<Mesh, SolverType>::M_comm->MyPID() == 0)
907  {
908  std::cout << "Total ionmodelsolve time " << chronoionmodelsolve.diff() << " s." << std::endl;
909  }
910 }
911 
912 
913 
914 template<typename Mesh, typename SolverType>
915 void LuoRudy<Mesh, SolverType>::computeODECoefficients ( const Real& u_ig )
916 {
917  if (u_ig >= -40.)
918  {
919  M_ah = 0.;
920  M_bh = 1. / (0.13 * (1. + std::exp ( (u_ig + 10.66) / (-11.1) ) ) );
921  M_aj = 0.;
922  M_bj = 0.3 * std::exp (-2.535e-7 * u_ig) / (1. + std::exp (-0.1 * (u_ig + 32.) ) );
923  }
924  else
925  {
926  M_ah = 0.135 * std::exp ( (80. + u_ig) / -6.8);
927  M_bh = 3.56 * std::exp (0.079 * u_ig) + 3.1e5 * std::exp (0.35 * u_ig);
928  M_aj = (-1.2714e5 * std::exp (0.2444 * u_ig) - 3.474e-5 * std::exp (-0.04391 * u_ig) ) *
929  (u_ig + 37.78) / (1 + std::exp (0.311 * (u_ig + 79.23) ) );
930  M_bj = 0.1212 * std::exp (-0.01052 * u_ig) / (1. + std::exp (-0.1378 * (u_ig + 40.14) ) );
931  }
932  M_am = 0.32 * (u_ig + 47.13) / (1. - std::exp (-0.1 * (u_ig + 47.13) ) );
933  M_bm = 0.08 * std::exp (-u_ig / 11.);
934 
935  //slow inward current
936  M_ad = 0.095 * std::exp (-0.01 * (u_ig - 5.) ) / (1. + std::exp (-0.072 * (u_ig - 5.) ) );
937  M_bd = 0.07 * std::exp (-0.017 * (u_ig + 44.) ) / (1. + std::exp ( 0.05 * (u_ig + 44.) ) );
938  M_af = 0.012 * std::exp (-0.008 * (u_ig + 28.) ) / (1. + std::exp ( 0.15 * (u_ig + 28.) ) );
939  M_bf = 0.0065 * std::exp (-0.02 * (u_ig + 30.) ) / (1. + std::exp ( -0.2 * (u_ig + 30.) ) );
940 
941  //Time dependent potassium outward current
942  M_aX = 0.0005 * std::exp (0.083 * (u_ig + 50.) ) / (1. + std::exp (0.057 * (u_ig + 50.) ) );
943  M_bX = 0.0013 * std::exp (-0.06 * (u_ig + 20.) ) / (1. + std::exp (-0.04 * (u_ig + 20.) ) );
944 
945  if (u_ig <= -100)
946  {
947  M_xii = 1.;
948  }
949  else
950  {
951  M_xii = 2.837 * (std::exp (0.04 * (u_ig + 77.) ) - 1.) / ( (u_ig + 77.) * std::exp (0.04 * (u_ig + 35.) ) );
952  }
953  M_ak1 = 1.02 / (1. + std::exp (0.2385 * (u_ig - M_Ek1 - 59.215) ) );
954  M_bk1 = (0.49124 * std::exp (0.08032 * (u_ig - M_Ek1 + 5.476) ) +
955  std::exp (0.06175 * (u_ig - M_Ek1 - 594.31) ) ) / (1. + std::exp (-0.5143 * (u_ig - M_Ek1 + 4.753) ) );
956  //Plateau potassium outward current
957  M_Kp = 1. / (1. + std::exp ( (7.488 - u_ig) / 5.98) );
958 
959  M_K1inf = M_ak1 / (M_ak1 + M_bk1);
960  M_hinf = M_ah / (M_ah + M_bh);
961  M_tauh = 1. / (M_ah + M_bh);
962  M_jinf = M_aj / (M_aj + M_bj);
963  M_tauj = 1. / (M_aj + M_bj);
964  M_minf = M_am / (M_am + M_bm);
965  M_taum = 1. / (M_am + M_bm);
966  M_dinf = M_ad / (M_ad + M_bd);
967  M_taud = 1. / (M_ad + M_bd);
968  M_finf = M_af / (M_af + M_bf);
969  M_tauf = 1. / (M_af + M_bf);
970  M_Xinf = M_aX / (M_aX + M_bX);
971  M_tauX = 1. / (M_aX + M_bX);
972 }
973 
974 template<typename Mesh, typename SolverType>
975 void LuoRudy<Mesh, SolverType>::computeIonicCurrent ( Real Capacitance,
976  VectorElemental& elvec,
977  VectorElemental& /*elvec_u*/,
978  FESpace<Mesh, MapEpetra>& uFESpace )
979 {
980  Real Iion_ig;
981  for ( UInt ig = 0; ig < uFESpace.fe().nbQuadPt(); ig++ )
982  {
983  Iion_ig = 0.;
984  for ( UInt i = 0; i < uFESpace.fe().nbFEDof(); i++ )
985  {
986  Iion_ig += M_elemVecIonicCurrent ( i ) * uFESpace.fe().phi ( i, ig );
987  }
988  for ( UInt i = 0; i < uFESpace.fe().nbFEDof(); i++ )
989  {
990  // divide by 1000 to convert microA in mA
991  elvec ( i ) -= Iion_ig * Capacitance *
992  uFESpace.fe().phi ( i, ig ) * uFESpace.fe().weightDet ( ig );
993  }
994  }
995 }
996 
997 template<typename Mesh, typename SolverType>
998 void LuoRudy<Mesh, SolverType>::
1000 {
1001  M_solutionGatingH.epetraVector().PutScalar (1.);
1002  M_solutionGatingJ.epetraVector().PutScalar (1.);
1003  M_solutionGatingM.epetraVector().PutScalar (0.);
1004  M_solutionGatingD.epetraVector().PutScalar (0.);
1005  M_solutionGatingF.epetraVector().PutScalar (1.);
1006  M_solutionGatingX.epetraVector().PutScalar (0.);
1007  M_solutionGatingCa.epetraVector().PutScalar (0.0002);
1008  M_solutionGatingH.globalAssemble();
1009  M_solutionGatingJ.globalAssemble();
1010  M_solutionGatingM.globalAssemble();
1011  M_solutionGatingD.globalAssemble();
1012  M_solutionGatingF.globalAssemble();
1013  M_solutionGatingX.globalAssemble();
1014  M_solutionGatingCa.globalAssemble();
1015 }
1016 
1017 } // namespace LifeV
1018 
1019 
1020 #endif //_IONICSOLVER_H_
HeartIonicSolver< Mesh, SolverType >::function_Type function_Type
SolverType::vector_type vector_Type
vector_Type M_solutionGatingW
Global solution _w.
void computeIonicCurrent(Real Capacitance, VectorElemental &elvec, VectorElemental &elvec_u, FESpace< Mesh, MapEpetra > &uFESpace)
Computes the term -1/ u^n (G (1-u^n/vp) (1-u^n/v_th) + eta_1 v^{n+1}) for the PDE righthand side...
void solveIonicModel(const vector_Type &u, const Real timeStep)
Solves the ionic model.
void setHeteroTauClose(functorTauClose_Type)
SolverType::matrix_type matrix_Type
void updateElementSolution(UInt eleID)
Update the ionic model elvecs.
HeartIonicSolver< Mesh, SolverType >::data_Type data_Type
void computeIonicCurrent(Real Capacitance, VectorElemental &elvec, VectorElemental &elvec_u, FESpace< Mesh, MapEpetra > &uFESpace)
Computes the term -1/ u^n (G (1-u^n/vp) (1-u^n/v_th) + eta_1 v^{n+1}) for the PDE righthand side...
HeartIonicSolver< Mesh, SolverType >::function_Type function_Type
const vector_Type & solutionGatingJ() const
const vector_Type & solutionGatingX() const
SolverType::prec_type prec_Type
vector_Type M_vectorExponentialf
vector_Type M_vectorInfimumj
HeartIonicSolver< Mesh, SolverType >::functorTauClose_Type functorTauClose_Type
virtual void solveIonicModel(const vector_Type &u, const Real timeStep)=0
Solves the ionic model.
FESpace - Short description here please!
Definition: FESpace.hpp:78
FESpace< Mesh, MapEpetra > & recoveryFESpace()
Returns the recovery variable FE space.
std::function< Real(const markerID_Type &ref, const Real &x, const Real &y, const Real &z, const ID &i) > functorTauClose_Type
vector_Type M_vectorExponentialj
const vector_Type & solutionGatingH() const
Returns the local solution vector for each field.
vector_Type M_vectorInfimumf
vector_Type M_ionicCurrentRepeated
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
RogersMcCulloch(const data_Type &dataType, const Mesh &mesh, FESpace< Mesh, MapEpetra > &uFEspace, Epetra_Comm &comm)
Constructor.
ID markerID_Type
markerID_Type is the type used to store the geometric entity marker IDs
Definition: Marker.hpp:81
TimeAdvanceBDF< vector_Type > M_BDFW
virtual void updateRepeated()=0
HeartIonicSolver(const data_Type &dataType, const Mesh &mesh, FESpace< Mesh, MapEpetra > &uFEspace, Epetra_Comm &comm)
Constructor.
HeartIonicSolver< Mesh, SolverType >::vector_Type vector_Type
HeartIonicSolver< Mesh, SolverType >::data_Type data_Type
void initialize()
Initialize.
HeartIonicSolver< Mesh, SolverType >::vector_Type vector_Type
MitchellSchaeffer(const data_Type &dataType, const Mesh &mesh, FESpace< Mesh, MapEpetra > &uFEspace, Epetra_Comm &comm)
Constructor.
Epetra_Import const & importer()
Getter for the Epetra_Import.
Definition: MapEpetra.cpp:394
void updateElementSolution(UInt eleID)
Update the ionic model elvecs.
void initialize()
Initialize.
uint32_type ID
IDs.
Definition: LifeV.hpp:194
HeartIonicSolver< Mesh, SolverType >::function_Type function_Type
vector_Type M_solutionGatingF
Global solution f.
SolverType::prec_raw_type precRaw_Type
virtual ~HeartIonicSolver()
Destructor.
vector_Type M_solutionGatingH
Global solution h.
vector_Type M_vectorExponentialm
vector_Type M_solutionGatingW
Global solution _w.
class TimeAdvanceBDF - Backward differencing formula time discretization for the first and the second...
vector_Type M_solutionGatingX
Global solution X.
Real functorTauClose(const markerID_Type &ref, const Real &x, const Real &y, const Real &z, const ID &i) const
void updateElementSolution(UInt eleID)
Update the ionic model elvecs.
void computeODECoefficients(const Real &u_ig)
HeartIonicSolver< Mesh, SolverType >::vector_Type vector_Type
virtual void computeIonicCurrent(Real Capacitance, VectorElemental &elvec, VectorElemental &elvec_u, FESpace< Mesh, MapEpetra > &uFESpace)=0
Computes the term -1/ u^n (G (1-u^n/vp) (1-u^n/v_th) + eta_1 v^{n+1}) for the PDE righthand side...
void solveIonicModel(const vector_Type &u, const Real timeStep)
Solves the ionic model.
double Real
Generic real data.
Definition: LifeV.hpp:175
void initialize()
Initialize.
virtual void initialize()=0
Initialize.
functorTauClose_Type M_tauClose
void computeIonicCurrent(Real Capacitance, VectorElemental &elvec, VectorElemental &elvec_u, FESpace< Mesh, MapEpetra > &uFESpace)
Computes the term -1/ u^n (G (1-u^n/vp) (1-u^n/v_th) + eta_1 v^{n+1}) for the PDE righthand side...
VectorElemental M_elemVecIonicCurrent
LuoRudy(const data_Type &dataType, const Mesh &mesh, FESpace< Mesh, MapEpetra > &uFEspace, Epetra_Comm &comm)
Constructor.
Epetra_Comm * M_comm
MPI communicator.
vector_Type M_vectorExponentialh
vector_Type M_solutionGatingJ
Global solution j.
vector_Type M_vectorInfimumd
vector_Type M_ionicCurrent
const vector_Type & solutionGatingM() const
bool M_verbose
Boolean that indicates if output is sent to cout.
const vector_Type & solutionGatingD() const
vector_Type M_solutionGatingD
Global solution d.
vector_Type M_vectorInfimumm
const vector_Type & solutionGatingW() const
vector_Type M_solutionGatingM
Global solution m.
vector_Type M_vectorExponentiald
vector_Type M_vectorIonicChange
const vector_Type & solutionGatingCa() const
const vector_Type & solutionGatingW() const
vector_Type M_solutionGatingCa
Global solution Ca_i.
vector_Type M_solutionGatingWRepeated
FESpace< Mesh, MapEpetra > & M_uFESpace
const vector_Type & solutionGatingF() const
virtual void updateElementSolution(UInt eleIDw)=0
Update the ionic model elvecs.
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191
vector_Type M_vectorInfimumX
void solveIonicModel(const vector_Type &u, const Real timeStep)
Solves the ionic model.
vector_Type M_vectorExponentialX
vector_Type M_vectorInfimumh
HeartIonicSolver< Mesh, SolverType >::data_Type data_Type