CEPS  24.01
Cardiac ElectroPhysiology Simulator
IonicSolver.cpp
Go to the documentation of this file.
1 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2  This file is part of CEPS.
3 
4  CEPS is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  CEPS is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with CEPS (see file LICENSE at root of project).
16  If not, see <https://www.gnu.org/licenses/>.
17 
18 
19  Copyright 2019-2024 Inria, Universite de Bordeaux
20 
21  Authors, in alphabetical order:
22 
23  Pierre-Elliott BECUE, Florian CARO, Yves COUDIERE(*), Andjela DAVIDOVIC,
24  Charlie DOUANLA-LONTSI, Marc FUENTES, Mehdi JUHOOR, Michael LEGUEBE(*),
25  Pauline MIGERDITICHAN, Valentin PANNETIER(*), Nejib ZEMZEMI.
26  * : currently active authors
27 
28 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
33 
35  CepsString solverOpts,
38 ):
39  m_model (m),
40  m_fLin (nullptr),
41  m_fNLin (nullptr),
42  m_sDiscr (sDiscr),
43  m_solver (nullptr),
44  m_y (nullptr),
45  m_dtyLin (nullptr),
46  m_dtyNLin (nullptr),
47  m_v (nullptr),
48  m_dtv (nullptr),
49  m_tauOk (false),
50  m_localToGlobal({}),
51  m_size (0)
52 {
54  "Pointer to ionic model is null"
55  );
57  "Pointer to spatial discretization is null"
58  );
59 
60  m_model->setLinkedSolver(this);
61 
62  // Convert the members of the ionic model into ceps::MemberFunction callable objects
65 
67  createSolvers(solverOpts);
69 }
70 
72 {
74 
77 
83 }
84 
85 void
87 {
88  vPde->getLocalData();
89  for (CepsUInt i=0;i<m_size;i++)
91  vPde->releaseLocalData();
92 
93 }
94 
95 void
97 {
98  setActionPotential(vPde);
99  m_solver->takeOneStep(t,dt);
100  m_tauOk = false;
101 }
102 
103 void
105 {
106  setActionPotential(vPde);
107  m_solver->takeOneSubStep(t,dt);
108  m_tauOk = false;
109 }
110 
111 void
113 {
114 
115  dtv->getLocalData();
116  for (CepsUInt i=0; i<m_size; i++)
117  {
118  CepsUInt gId = m_localToGlobal[i];
120  (*dtv)[gId] += val;
121  }
122  dtv->releaseLocalData();
123 }
124 
125 void
127 {
128  vPde->getLocalData();
129  for (CepsUInt i=0;i<m_size;i++)
131  vPde->releaseLocalData();
132 }
133 
134 CepsReal
136 {
137  if (convert)
139  return *m_v;
140 }
141 
142 CepsReal*
144 {
145  return m_y;
146 }
147 
148 CepsReal*
150 {
151  return m_dtv;
152 }
153 
154 CepsUInt
156 {
157  return m_solver->getNbMultiSteps();
158 }
159 
160 // Protected ---------------------------------------------------------------------------------------
161 
162 void
164 {
166  auto mattrs = m_model->getAttributes();
167 
168  for (DegreeOfFreedom* dof : dofs)
169  {
170  if (dof->getOwner()==ceps::getRank() and
171  (mattrs.empty() or dof->hasOneOfAttributes(mattrs) or mattrs.contains(CepsUniversal)))
172  m_localToGlobal.push_back(dof->getGlobalIndex());
173  }
174 }
175 
176 void
178 {
179 
180  std::istringstream iss(opts);
181 
182  CEPS_ABORT_IF(opts.empty(),
183  "Could not read options of ionic model solver"
184  );
185 
186  CepsString type;
187  CepsUInt order;
188  iss >> type;
189  type = ceps::toUpper(type);
190 
191  if (type == "EULER" or type == "EXPLICIT_EULER")
192  {
193  m_solver = ceps::getNew<ExplicitEulerOdeSolver>();
194  }
195 
196  else if (type == "IMPLICIT_EULER" or type == "FBE")
197  {
198  m_solver = ceps::getNew<FBEOdeSolver>();
199  }
200 
201  else if (type == "RUSH_LARSEN" or type == "RL")
202  {
203  order = ceps::readInt(iss,"Ionic solver: missing order for Rush-Larsen ODE solver");
204  m_solver = ceps::getNew<RushLarsenOdeSolver>(order);
205  }
206 
207  else if (type == "EXP_ADAMS_BASHFORTH" or type == "EAB")
208  {
209  order = ceps::readInt(iss,"Ionic solver: missing order for Adams-Bashforth ODE solver");
210  m_solver = ceps::getNew<ExponentialAdamsBashforthOdeSolver>(order);
211  }
212 
213  else if (type == "RUNGE_KUTTA" or type == "RK")
214  {
215  CepsString opt;
216  iss >> opt;
217  CEPS_ABORT_IF(opt.empty(),
218  "Ionic solver : missing type of Runge-Kutta ODE solver"
219  );
220  m_solver = ceps::getNew<RungeKuttaOdeSolver>(opt);
221  }
222 
223  else if (type == "SBDF" or type == "BACKWARD_DIFFERENTIATION")
224  {
225  order = ceps::readInt(iss,"Ionic solver: missing order for SBDF ODE solver");
226  m_solver = ceps::getNew<SBDFOdeSolver>(order);
227  }
228 
229  else
230  CEPS_ABORT("Unknown solver type. Valid types are \n"
231  << " - EXPLICIT_EULER (or just EULER)\n"
232  << " - IMPLICIT_EULER (or FBE)\n"
233  << " - RUSH_LARSEN <1-4> (or RL <1-4>)\n"
234  << " - EXP_ADAMS_BASHFORTH <1-4> (or EAB <1-4>)\n"
235  << " - BACKWARD_DIFFERENTIATION <1-4> (or SBDF <1-4>)\n"
236  << " - RUNGE_KUTTA <opt> (or RK <opt>)\n"
237  << " where opt can be an integer between 1 and 5 or\n"
238  << " Heun2 Heun3\n"
239  << " Ralston3 SSP3 38 Ralston4\n"
240  << " Nystrom5 Fehlberg5.");
241 
242 }
243 
244 void
246 {
247 
248  // Allocate arrays
249  m_size = m_localToGlobal.size();
251 
252  m_y = ceps::newArray<CepsReal>(m_size*nVars);
253  m_dtyLin = ceps::newArray<CepsReal>(m_size*nVars);
254  m_dtyNLin = ceps::newArray<CepsReal>(m_size*nVars);
255  m_v = ceps::newArray<CepsReal>(m_size);
256  m_dtv = ceps::newArray<CepsReal>(m_size);
257 
258  // Build the initial condition vector, also sets the PDE vector
259  for (CepsUInt i=0;i<m_size;i++)
260  {
261  m_model->getInitialCondition(m_v+i,m_y+i*nVars);
262  //m_dtv[i] = 0.;
263  }
264  // Computes m_dtv with provided initial conditions (not necessarily steady state)
265  this->computeModelRates(0.,m_y);
266  m_tauOk = false;
267 
268  // Initialize solver with initial condition data and link to linear/non linear evaluation calls
269  m_solver->initialize(m_y,m_size*nVars,m_fNLin,m_fLin,false);
270 
271 }
272 
273 void
275 {
276 
278 
279  // Loop on all dofs
280  for (CepsUInt i=0; i<m_size; i++)
281  {
282 
283  CepsReal* y = Y + i*nVars;
284  CepsReal* v = m_v + i;
285  CepsReal* dtyLin = m_dtyLin + i*nVars;
286  CepsReal* dtyNLin = m_dtyNLin + i*nVars;
287  CepsReal* dtv = m_dtv + i;
288 
290 
291  m_model->computeRates(t,y,v,dtyLin,dtyNLin,dtv,dof);
292  }
293 
294  m_tauOk = true;
295 }
296 
297 void
299 {
300  if (not m_tauOk)
301  computeModelRates(t,y);
302  std::copy(m_dtyLin,m_dtyLin+n,res);
303 }
304 
305 void
307 {
308  if (not m_tauOk)
309  computeModelRates(t,y);
310  std::copy(m_dtyNLin,m_dtyNLin+n,res);
311 }
#define CEPS_ABORT(message)
Stops the execution with a message. If testing is enabled, only throws a runtime_error.
#define CEPS_ABORT_IF(condition, message)
Stops the execution with a message if condition is true. If testing is enabled, only throws a runtime...
std::basic_string< CepsChar > CepsString
C++ format string.
Definition: CepsTypes.hpp:128
bool CepsBool
Booleans.
Definition: CepsTypes.hpp:124
std::make_unsigned_t< CepsInt > CepsUInt
Unsigned version on CepsInt.
Definition: CepsTypes.hpp:109
float CepsReal
Need single precision floating point.
Definition: CepsTypes.hpp:100
constexpr CepsAttribute CepsUniversal
This attribute means "everywhere".
Definition: CepsTypes.hpp:232
std::shared_ptr< DistributedHaloVector > DHVecPtr
Typedef for pointer on Distributed Halo CepsVector.
Abstract Class for all numerical method (FE, FD, FV etc)
const CepsMap< CepsUnknownIndex, CepsVector< DegreeOfFreedom * > > & getDegreesOfFreedomForUnknown()
Dofs sorted by unknown.
DegreeOfFreedom * getDof(CepsGlobalIndex globalDofId)
Get the dof with given globalID, nullptr if not found.
Represents a ionic model for a group of cells, i.e. multiple systems of ODEs.
Unknown * getUnknown() const
The unknown object of the transmembrane voltage.
virtual CepsReal convertDtvToCepsUnit(const CepsReal &dtv) const
Convert current from ionic model units to ceps units (mV ms-1). Does nothing by default.
virtual void computeRates(CepsReal t, CepsReal *y, CepsReal *v, CepsReal *dtyL, CepsReal *dtyNL, CepsReal *dtv, DegreeOfFreedom *dof) const =0
Get the linear and non linear part of the evolution function f. Also computes the ionic current.
virtual CepsUInt getNbStateVariables() const
The number of state variables, except transmembrane voltage.
virtual CepsReal convertVoltageToCepsUnit(const CepsReal &v) const
Convert voltage from ionic model units to ceps units (mV). Does nothing by default.
virtual CepsReal convertVoltageFromCepsUnit(const CepsReal &v) const
Convert voltage from ceps units (mV) to ionic model units. Does nothing by default.
virtual void getInitialCondition(CepsReal *v, CepsReal *y) const =0
Sets initial values of state variables and transmembrane voltage for a single point....
void setLinkedSolver(IonicSolver *solver)
Links instance to solver.
virtual void takeOneSubStep(CepsReal t, CepsReal dt)
Progress by a substep, for RK methods. Does nothing by default.
virtual void initialize(CepsReal *y0, CepsUInt n, RateFunction *nonlinearFunc, RateFunction *linearFunc=nullptr, CepsBool copy=false)
Allocate data arrays and sets initial condition with given data.
virtual void takeOneStep(CepsReal t, CepsReal dt)=0
Make a full ode step : must be defined in every child class.
CepsUInt getNbMultiSteps() const
Tells how many time steps the method covers.
A degree of freedom for any kind of problem The dof can be associated to a geometrical element or not...
CepsUInt m_size
Number of dofs for this solver.
CepsReal * m_y
Values of state variables.
CepsVector< CepsIndex > m_localToGlobal
Mapping between local index of dof and index in PDE.
void computeModelRates(CepsReal t, CepsReal *y)
Computes the evolution function and ionic current on all dofs, calls the model.
CepsBool m_tauOk
Flag to avoid to compute tau and winf twice per iteration.
CepsReal * m_dtv
Total ionic current.
void fillPdeVm(DHVecPtr vPde) const
Fills the linked PDE vector for vm with current values of m_v. Can be used to get initial condition.
CepsUInt getNbMultiSteps() const
Number of multi steps of the inner solver.
AbstractIonicModel * m_model
Link to ionic model equations.
void computeRatesLin(CepsReal t, CepsReal *w, CepsReal *dtw, CepsUInt n)
Call the linear part of evolution function of the model.
void createSolvers(CepsString opts)
Instantiates ODE solvers from options.
~IonicSolver()
Destructor.
Definition: IonicSolver.cpp:71
CepsReal * m_v
Transmembrane voltage.
void addDtv(DHVecPtr dtv, CepsReal t=0) const
Fills the given distributed vector with values of ionic current from ODE system. Does the unit conver...
void takeOneSubStep(CepsReal t, CepsReal dt, DHVecPtr vPde)
Advance the ODE system by one sub step (for RK solvers)
CepsReal * m_dtyLin
Linear part of rates.
CepsReal * getStates() const
Get pointer on state vars for testing purposes.
CepsReal * getDtv() const
Get pointer on ionic current for testing purposes.
AbstractOdeSolver * m_solver
internal ODE solver
CepsReal * m_dtyNLin
Non-linear part of rates.
void takeOneStep(CepsReal t, CepsReal dt, DHVecPtr vPde)
Advance the ODE system by one full step each (not substep)
Definition: IonicSolver.cpp:96
void computeIndexMapping()
Sets the map from instance-local indices of points to global indices, then allocates arrays and sets ...
IonicSolver(CepsString opts, AbstractIonicModel *m, AbstractDiscretization *discr)
Constructor with parameters from input file and ionic model to be linked with The constructor also se...
Definition: IonicSolver.cpp:34
CepsReal getVm(CepsBool convert) const
Get TMV for testing purposes.
void setActionPotential(DHVecPtr vPde)
Copies values of TMV from PDE vector to local array. Call this method prior to takeOneStep or takeOne...
Definition: IonicSolver.cpp:86
EvolFunction * m_fNLin
Evolution function (non linear part winf/tau + others)
void initializeSolver()
Set the initial conditions and required intermediate arrays of the ODE solvers.
void computeRatesNonLin(CepsReal t, CepsReal *w, CepsReal *dtw, CepsUInt n)
Get the non linear part of evolution function of the model.
AbstractDiscretization * m_sDiscr
Link to spatial discretization.
EvolFunction * m_fLin
Evolution function (linear part -1/tau)
CepsSet< CepsAttribute > & getAttributes()
Returns the attributes of the entity.
auto newFunction(_Class obj, _Res(_Class::*fn)(_Args...)) noexcept
Transforms a member function of class into a MemberFunction struct.
CepsUInt getRank()
Returns current processor rank.
void destroyTabular(_Type &)
Destroy[delete] any type.
Definition: CepsMemory.hpp:149
CepsInt readInt(std::istream &file, const CepsString &errorMessage="")
Reads an integral number from an istream, aborts if conversion fails advances the stream by 1 word.
Definition: CepsString.cpp:677
CepsBool isNullPtr(_Type *ptr)
Tells if passed pointer is null.
Definition: CepsMemory.hpp:45
CepsString toUpper(const CepsString &s)
Switches all characters to upper case.
Definition: CepsString.cpp:124
void destroyObject(_Type &)
Destroy[delete] any type.
Definition: CepsMemory.hpp:116