Nektar++
CourtemancheRamirezNattel98.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: CourtemancheRamirezNattel98.cpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Courtemanche-Ramirez-Nattel ionic atrial cell model.
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #include <iostream>
36 #include <string>
37 
40 
41 using namespace std;
42 
43 namespace Nektar
44 {
45 std::string CourtemancheRamirezNattel98::className =
47  "CourtemancheRamirezNattel98", CourtemancheRamirezNattel98::create,
48  "Ionic model of human atrial cell electrophysiology.");
49 
50 // Register cell model variants
51 std::string CourtemancheRamirezNattel98::lookupIds[2] = {
52  LibUtilities::SessionReader::RegisterEnumValue(
53  "CellModelVariant", "Original", CourtemancheRamirezNattel98::eOriginal),
54  LibUtilities::SessionReader::RegisterEnumValue(
55  "CellModelVariant", "AF", CourtemancheRamirezNattel98::eAF)};
56 
57 // Register default variant
58 std::string CourtemancheRamirezNattel98::def =
59  LibUtilities::SessionReader::RegisterDefaultSolverInfo("CellModelVariant",
60  "Original");
61 
62 /**
63  *
64  */
65 CourtemancheRamirezNattel98::CourtemancheRamirezNattel98(
67  const MultiRegions::ExpListSharedPtr &pField)
68  : CellModel(pSession, pField)
69 {
71  pSession->GetSolverInfoAsEnum<CourtemancheRamirezNattel98::Variants>(
72  "CellModelVariant");
73 
74  C_m = 100; // picoF
75  g_Na = 7.8; // nanoS_per_picoF
76  g_K1 = 0.09; // nanoS_per_picoF
77  g_Kr = 0.029411765;
78  g_Ks = 0.12941176;
79  g_b_Na = 0.0006744375;
80  g_b_Ca = 0.001131;
81  R = 8.3143;
82  T = 310.0;
83  F = 96.4867;
84  Na_o = 140.0; // millimolar
85  K_o = 5.4; // millimolar
86  sigma = 1.0 / 7.0 * (exp(Na_o / 67.3) - 1);
87  K_i = 1.5;
88  K_m_Na_i = 10.0;
89  I_Na_K_max = 0.59933874;
90  I_NaCa_max = 1600.0;
91  gamma = 0.35;
92  Ca_o = 1.8;
93  K_m_Na = 87.5;
94  K_m_Ca = 1.38;
95  K_sat = 0.1;
96  I_p_Ca_max = 0.275;
97  Trpn_max = 0.07;
98  Km_Trpn = 0.0005;
99  Cmdn_max = 0.05;
100  Csqn_max = 10.0;
101  Km_Cmdn = 0.00238;
102  Km_Csqn = 0.8;
103  NSR_I_up_max = 0.005;
104  NSR_I_Ca_max = 15.0;
105  NSR_K_up = 0.00092;
106  JSR_K_rel = 30.0;
107  JSR_V_cell = 20100.0;
108  JSR_V_rel = 0.0048 * JSR_V_cell;
109  JSR_V_up = 0.0552 * JSR_V_cell;
110  tau_tr = 180.0;
111  K_Q10 = 3.0;
112  V_i = 0.68 * JSR_V_cell;
113 
114  switch (model_variant)
115  {
116  case eOriginal:
117  g_to = 0.1652; // nanoS_per_picoF
118  g_Kur_scaling = 1.0;
119  g_Ca_L = 0.12375;
120  break;
121  case eAF:
122  g_to = 0.0826; // nanoS_per_picoF
123  g_Kur_scaling = 0.5;
124  g_Ca_L = 0.037125;
125  break;
126  }
127 
128  m_nvar = 21;
129 
130  // List gates and concentrations
131  m_gates.push_back(1);
132  m_gates.push_back(2);
133  m_gates.push_back(3);
134  m_gates.push_back(4);
135  m_gates.push_back(5);
136  m_gates.push_back(6);
137  m_gates.push_back(7);
138  m_gates.push_back(8);
139  m_gates.push_back(9);
140  m_gates.push_back(10);
141  m_gates.push_back(11);
142  m_gates.push_back(12);
143  m_gates.push_back(13);
144  m_gates.push_back(14);
145  m_gates.push_back(15);
146  m_concentrations.push_back(16);
147  m_concentrations.push_back(17);
148  m_concentrations.push_back(18);
149  m_concentrations.push_back(19);
150  m_concentrations.push_back(20);
151 }
152 
153 /**
154  *
155  */
157 {
158 }
159 
161  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
162  Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time)
163 {
164  boost::ignore_unused(time);
165  ASSERTL0(inarray.get() != outarray.get(),
166  "Must have different arrays for input and output.");
167 
168  // Variables
169  // 0 V membrane potential
170  // 2 m fast sodium current m gate
171  // 3 h fast sodium current h gate
172  // 4 j fast sodium current j gate
173  // 5 o_a transient outward potassium o_a gate
174  // 6 o_i transient outward potassium o_i gate
175  // 7 u_a ultra-rapid delayed rectifier K current gate
176  // 8 u_i ultra-rapid delayed rectifier K current gate
177  // 9 x_r rapid delayed rectifier K current gate
178  // 10 x_s slow delayed rectifier K current gate
179  // 11 d L_type calcium gate
180  // 12 f L-type calcium gate
181  // 13 f_Ca L-type calcium gate
182  // 14 u Ca release u gate
183  // 15 v Ca release v gate
184  // 16 w Ca release w gate
185  // 17 Na_i Sodium
186  // 18 Ca_i Calcium
187  // 19 K_i Potassium
188  // 20 Ca_rel Calcium Rel
189  // 21 Ca_up Calcium up
190  size_t n = m_nq;
191  size_t i = 0;
192  NekDouble alpha, beta;
193  Vmath::Zero(n, outarray[0], 1);
194 
195  Array<OneD, NekDouble> &tmp = outarray[11];
196  Array<OneD, NekDouble> &tmp2 = outarray[12];
197 
198  // E_Na
199  Array<OneD, NekDouble> &tmp_E_na = outarray[14];
200  Vmath::Sdiv(n, Na_o, inarray[16], 1, tmp_E_na, 1);
201  Vmath::Vlog(n, tmp_E_na, 1, tmp_E_na, 1);
202  Vmath::Smul(n, R * T / F, tmp_E_na, 1, tmp_E_na, 1);
203 
204  // Sodium I_Na
205  Array<OneD, NekDouble> &tmp_I_Na = outarray[15];
206  Vmath::Vsub(n, inarray[0], 1, tmp_E_na, 1, tmp_I_Na, 1);
207  Vmath::Vmul(n, inarray[1], 1, tmp_I_Na, 1, tmp_I_Na, 1);
208  Vmath::Vmul(n, inarray[1], 1, tmp_I_Na, 1, tmp_I_Na, 1);
209  Vmath::Vmul(n, inarray[1], 1, tmp_I_Na, 1, tmp_I_Na, 1);
210  Vmath::Vmul(n, inarray[2], 1, tmp_I_Na, 1, tmp_I_Na, 1);
211  Vmath::Vmul(n, inarray[3], 1, tmp_I_Na, 1, tmp_I_Na, 1);
212  Vmath::Smul(n, C_m * g_Na, tmp_I_Na, 1, tmp_I_Na, 1);
213  Vmath::Vsub(n, outarray[0], 1, tmp_I_Na, 1, outarray[0], 1);
214  Vmath::Smul(n, -1.0, tmp_I_Na, 1, outarray[16], 1);
215 
216  // Background current, sodium
217  Array<OneD, NekDouble> &tmp_I_b_Na = outarray[15];
218  Vmath::Vsub(n, inarray[0], 1, tmp_E_na, 1, tmp_I_b_Na, 1);
219  Vmath::Smul(n, C_m * g_b_Na, tmp_I_b_Na, 1, tmp_I_b_Na, 1);
220  Vmath::Vsub(n, outarray[0], 1, tmp_I_b_Na, 1, outarray[0], 1);
221  Vmath::Vsub(n, outarray[16], 1, tmp_I_b_Na, 1, outarray[16], 1);
222 
223  // V - E_K
224  Array<OneD, NekDouble> &tmp_V_E_k = outarray[14];
225  Vmath::Sdiv(n, K_o, inarray[18], 1, tmp_V_E_k, 1);
226  Vmath::Vlog(n, tmp_V_E_k, 1, tmp_V_E_k, 1);
227  Vmath::Smul(n, R * T / F, tmp_V_E_k, 1, tmp_V_E_k, 1);
228  Vmath::Vsub(n, inarray[0], 1, tmp_V_E_k, 1, tmp_V_E_k, 1);
229 
230  // Potassium I_K1
231  Array<OneD, NekDouble> &tmp_I_K1 = outarray[15];
232  Vmath::Sadd(n, 80.0, inarray[0], 1, tmp_I_K1, 1);
233  Vmath::Smul(n, 0.07, tmp_I_K1, 1, tmp_I_K1, 1);
234  Vmath::Vexp(n, tmp_I_K1, 1, tmp_I_K1, 1);
235  Vmath::Sadd(n, 1.0, tmp_I_K1, 1, tmp_I_K1, 1);
236  Vmath::Vdiv(n, tmp_V_E_k, 1, tmp_I_K1, 1, tmp_I_K1, 1);
237  Vmath::Smul(n, C_m * g_K1, tmp_I_K1, 1, tmp_I_K1, 1);
238  Vmath::Vsub(n, outarray[0], 1, tmp_I_K1, 1, outarray[0], 1);
239  Vmath::Smul(n, -1.0, tmp_I_K1, 1, outarray[18], 1);
240 
241  // Transient Outward K+ current
242  Array<OneD, NekDouble> &tmp_I_to = outarray[15];
243  Vmath::Vmul(n, inarray[5], 1, tmp_V_E_k, 1, tmp_I_to, 1);
244  Vmath::Vmul(n, inarray[4], 1, tmp_I_to, 1, tmp_I_to, 1);
245  Vmath::Vmul(n, inarray[4], 1, tmp_I_to, 1, tmp_I_to, 1);
246  Vmath::Vmul(n, inarray[4], 1, tmp_I_to, 1, tmp_I_to, 1);
247  Vmath::Smul(n, C_m * g_to, tmp_I_to, 1, tmp_I_to, 1);
248  Vmath::Vsub(n, outarray[0], 1, tmp_I_to, 1, outarray[0], 1);
249  Vmath::Vsub(n, outarray[18], 1, tmp_I_to, 1, outarray[18], 1);
250 
251  // Ultrarapid Delayed rectifier K+ current
252  Array<OneD, NekDouble> &tmp_I_kur = outarray[15];
253  Vmath::Sadd(n, -15.0, inarray[0], 1, tmp_I_kur, 1);
254  Vmath::Smul(n, -1.0 / 13.0, tmp_I_kur, 1, tmp_I_kur, 1);
255  Vmath::Vexp(n, tmp_I_kur, 1, tmp_I_kur, 1);
256  Vmath::Sadd(n, 1.0, tmp_I_kur, 1, tmp_I_kur, 1);
257  Vmath::Sdiv(n, 0.05, tmp_I_kur, 1, tmp_I_kur, 1);
258  Vmath::Sadd(n, 0.005, tmp_I_kur, 1, tmp_I_kur, 1);
259  Vmath::Vmul(n, tmp_V_E_k, 1, tmp_I_kur, 1, tmp_I_kur, 1);
260  Vmath::Vmul(n, inarray[6], 1, tmp_I_kur, 1, tmp_I_kur, 1);
261  Vmath::Vmul(n, inarray[6], 1, tmp_I_kur, 1, tmp_I_kur, 1);
262  Vmath::Vmul(n, inarray[6], 1, tmp_I_kur, 1, tmp_I_kur, 1);
263  Vmath::Vmul(n, inarray[7], 1, tmp_I_kur, 1, tmp_I_kur, 1);
264  Vmath::Smul(n, C_m * g_Kur_scaling, tmp_I_kur, 1, tmp_I_kur, 1);
265  Vmath::Vsub(n, outarray[0], 1, tmp_I_kur, 1, outarray[0], 1);
266  Vmath::Vsub(n, outarray[18], 1, tmp_I_kur, 1, outarray[18], 1);
267 
268  // Rapid delayed outward rectifier K+ current
269  Array<OneD, NekDouble> &tmp_I_Kr = outarray[15];
270  Vmath::Sadd(n, 15.0, inarray[0], 1, tmp_I_Kr, 1);
271  Vmath::Smul(n, 1.0 / 22.4, tmp_I_Kr, 1, tmp_I_Kr, 1);
272  Vmath::Vexp(n, tmp_I_Kr, 1, tmp_I_Kr, 1);
273  Vmath::Sadd(n, 1.0, tmp_I_Kr, 1, tmp_I_Kr, 1);
274  Vmath::Vdiv(n, tmp_V_E_k, 1, tmp_I_Kr, 1, tmp_I_Kr, 1);
275  Vmath::Vmul(n, inarray[8], 1, tmp_I_Kr, 1, tmp_I_Kr, 1);
276  Vmath::Smul(n, C_m * g_Kr, tmp_I_Kr, 1, tmp_I_Kr, 1);
277  Vmath::Vsub(n, outarray[0], 1, tmp_I_Kr, 1, outarray[0], 1);
278  Vmath::Vsub(n, outarray[18], 1, tmp_I_Kr, 1, outarray[18], 1);
279 
280  // Slow delayed outward rectifier K+ Current
281  Array<OneD, NekDouble> &tmp_I_Ks = outarray[15];
282  Vmath::Vmul(n, inarray[9], 1, tmp_V_E_k, 1, tmp_I_Ks, 1);
283  Vmath::Vmul(n, inarray[9], 1, tmp_I_Ks, 1, tmp_I_Ks, 1);
284  Vmath::Smul(n, C_m * g_Ks, tmp_I_Ks, 1, tmp_I_Ks, 1);
285  Vmath::Vsub(n, outarray[0], 1, tmp_I_Ks, 1, outarray[0], 1);
286  Vmath::Vsub(n, outarray[18], 1, tmp_I_Ks, 1, outarray[18], 1);
287 
288  // Background current, calcium
289  Array<OneD, NekDouble> &tmp_I_b_Ca = outarray[1];
290  Vmath::Sdiv(n, Ca_o, inarray[17], 1, tmp_I_b_Ca, 1);
291  Vmath::Vlog(n, tmp_I_b_Ca, 1, tmp_I_b_Ca, 1);
292  Vmath::Smul(n, 0.5 * R * T / F, tmp_I_b_Ca, 1, tmp_I_b_Ca, 1);
293  Vmath::Vsub(n, inarray[0], 1, tmp_I_b_Ca, 1, tmp_I_b_Ca, 1);
294  Vmath::Smul(n, C_m * g_b_Ca, tmp_I_b_Ca, 1, tmp_I_b_Ca, 1);
295  Vmath::Vsub(n, outarray[0], 1, tmp_I_b_Ca, 1, outarray[0], 1);
296 
297  // L-Type Ca2+ current
298  Array<OneD, NekDouble> &tmp_I_Ca_L = outarray[2];
299  Vmath::Sadd(n, -65.0, inarray[0], 1, tmp_I_Ca_L, 1);
300  Vmath::Vmul(n, inarray[10], 1, tmp_I_Ca_L, 1, tmp_I_Ca_L, 1);
301  Vmath::Vmul(n, inarray[11], 1, tmp_I_Ca_L, 1, tmp_I_Ca_L, 1);
302  Vmath::Vmul(n, inarray[12], 1, tmp_I_Ca_L, 1, tmp_I_Ca_L, 1);
303  Vmath::Smul(n, C_m * g_Ca_L, tmp_I_Ca_L, 1, tmp_I_Ca_L, 1);
304  Vmath::Vsub(n, outarray[0], 1, tmp_I_Ca_L, 1, outarray[0], 1);
305 
306  // Na-K Pump Current
307  Array<OneD, NekDouble> &tmp_f_Na_k = outarray[14];
308  Vmath::Smul(n, -F / R / T, inarray[0], 1, tmp_f_Na_k, 1);
309  Vmath::Vexp(n, tmp_f_Na_k, 1, tmp, 1);
310  Vmath::Smul(n, 0.0365 * sigma, tmp, 1, tmp, 1);
311  Vmath::Smul(n, -0.1 * F / R / T, inarray[0], 1, tmp_f_Na_k, 1);
312  Vmath::Vexp(n, tmp_f_Na_k, 1, tmp_f_Na_k, 1);
313  Vmath::Smul(n, 0.1245, tmp_f_Na_k, 1, tmp_f_Na_k, 1);
314  Vmath::Vadd(n, tmp_f_Na_k, 1, tmp, 1, tmp_f_Na_k, 1);
315  Vmath::Sadd(n, 1.0, tmp_f_Na_k, 1, tmp_f_Na_k, 1);
316 
317  Array<OneD, NekDouble> &tmp_I_Na_K = outarray[15];
318  Vmath::Sdiv(n, K_m_Na_i, inarray[16], 1, tmp_I_Na_K, 1);
319  Vmath::Vpow(n, tmp_I_Na_K, 1, 1.5, tmp_I_Na_K, 1);
320  Vmath::Sadd(n, 1.0, tmp_I_Na_K, 1, tmp_I_Na_K, 1);
321  Vmath::Vmul(n, tmp_f_Na_k, 1, tmp_I_Na_K, 1, tmp_I_Na_K, 1);
322  Vmath::Sdiv(n, C_m * I_Na_K_max * K_o / (K_o + K_i), tmp_I_Na_K, 1,
323  tmp_I_Na_K, 1);
324  Vmath::Vsub(n, outarray[0], 1, tmp_I_Na_K, 1, outarray[0], 1);
325  Vmath::Svtvp(n, -3.0, tmp_I_Na_K, 1, outarray[16], 1, outarray[16], 1);
326  Vmath::Svtvp(n, 2.0, tmp_I_Na_K, 1, outarray[18], 1, outarray[18], 1);
327 
328  // Na-Ca exchanger current
329  Array<OneD, NekDouble> &tmp_I_Na_Ca = outarray[3];
330  Vmath::Smul(n, (gamma - 1) * F / R / T, inarray[0], 1, tmp, 1);
331  Vmath::Vexp(n, tmp, 1, tmp, 1);
332  Vmath::Smul(n, K_sat, tmp, 1, tmp_I_Na_Ca, 1);
333  Vmath::Sadd(n, 1.0, tmp_I_Na_Ca, 1, tmp_I_Na_Ca, 1);
334  Vmath::Smul(
335  n, (K_m_Na * K_m_Na * K_m_Na + Na_o * Na_o * Na_o) * (K_m_Ca + Ca_o),
336  tmp_I_Na_Ca, 1, tmp_I_Na_Ca, 1);
337 
338  Vmath::Smul(n, Na_o * Na_o * Na_o, tmp, 1, tmp2, 1);
339  Vmath::Vmul(n, tmp2, 1, inarray[17], 1, tmp2, 1);
340  Vmath::Smul(n, gamma * F / R / T, inarray[0], 1, tmp, 1);
341  Vmath::Vexp(n, tmp, 1, tmp, 1);
342  Vmath::Vmul(n, inarray[16], 1, tmp, 1, tmp, 1);
343  Vmath::Vmul(n, inarray[16], 1, tmp, 1, tmp, 1);
344  Vmath::Vmul(n, inarray[16], 1, tmp, 1, tmp, 1);
345  Vmath::Svtvm(n, Ca_o, tmp, 1, tmp2, 1, tmp, 1);
346  Vmath::Smul(n, C_m * I_NaCa_max, tmp, 1, tmp, 1);
347  Vmath::Vdiv(n, tmp, 1, tmp_I_Na_Ca, 1, tmp_I_Na_Ca, 1);
348  Vmath::Vsub(n, outarray[0], 1, tmp_I_Na_Ca, 1, outarray[0], 1);
349  Vmath::Svtvp(n, -3.0, tmp_I_Na_Ca, 1, outarray[16], 1, outarray[16], 1);
350 
351  // Calcium Pump current
352  Array<OneD, NekDouble> &tmp_I_p_Ca = outarray[4];
353  Vmath::Sadd(n, 0.0005, inarray[17], 1, tmp_I_p_Ca, 1);
354  Vmath::Vdiv(n, inarray[17], 1, tmp_I_p_Ca, 1, tmp_I_p_Ca, 1);
355  Vmath::Smul(n, C_m * I_p_Ca_max, tmp_I_p_Ca, 1, tmp_I_p_Ca, 1);
356  Vmath::Vsub(n, outarray[0], 1, tmp_I_p_Ca, 1, outarray[0], 1);
357 
358  // Scale currents by capacitance
359  Vmath::Smul(n, 1.0 / C_m, outarray[0], 1, outarray[0], 1);
360 
361  // Scale sodium and potassium by FV_i
362  Vmath::Smul(n, 1.0 / F / V_i, outarray[16], 1, outarray[16], 1);
363  Vmath::Smul(n, 1.0 / F / V_i, outarray[18], 1, outarray[18], 1);
364 
365  // I_tr
366  Array<OneD, NekDouble> &tmp_I_tr = outarray[5];
367  Vmath::Vsub(n, inarray[20], 1, inarray[19], 1, tmp_I_tr, 1);
368  Vmath::Smul(n, 1.0 / tau_tr, tmp_I_tr, 1, tmp_I_tr, 1);
369 
370  // I_up_leak
371  Array<OneD, NekDouble> &tmp_I_up_leak = outarray[6];
372  Vmath::Smul(n, NSR_I_up_max / NSR_I_Ca_max, inarray[20], 1, tmp_I_up_leak,
373  1);
374 
375  // I_up
376  Array<OneD, NekDouble> &tmp_I_up = outarray[7];
377  Vmath::Sdiv(n, NSR_K_up, inarray[17], 1, tmp_I_up, 1);
378  Vmath::Sadd(n, 1.0, tmp_I_up, 1, tmp_I_up, 1);
379  Vmath::Sdiv(n, NSR_I_up_max, tmp_I_up, 1, tmp_I_up, 1);
380 
381  // I_rel
382  Array<OneD, NekDouble> &tmp_I_rel = outarray[8];
383  Vmath::Vsub(n, inarray[19], 1, inarray[17], 1, tmp_I_rel, 1);
384  Vmath::Vmul(n, tmp_I_rel, 1, inarray[13], 1, tmp_I_rel, 1);
385  Vmath::Vmul(n, tmp_I_rel, 1, inarray[13], 1, tmp_I_rel, 1);
386  Vmath::Vmul(n, tmp_I_rel, 1, inarray[14], 1, tmp_I_rel, 1);
387  Vmath::Vmul(n, tmp_I_rel, 1, inarray[15], 1, tmp_I_rel, 1);
388  Vmath::Smul(n, JSR_K_rel, tmp_I_rel, 1, tmp_I_rel, 1);
389 
390  // B1
391  Array<OneD, NekDouble> &tmp_B1 = outarray[9];
392  Vmath::Svtvm(n, 2.0, tmp_I_Na_Ca, 1, tmp_I_p_Ca, 1, tmp_B1, 1);
393  Vmath::Vsub(n, tmp_B1, 1, tmp_I_Ca_L, 1, tmp_B1, 1);
394  Vmath::Vsub(n, tmp_B1, 1, tmp_I_b_Ca, 1, tmp_B1, 1);
395  Vmath::Smul(n, 0.5 / F, tmp_B1, 1, tmp_B1, 1);
396  Vmath::Svtvp(n, JSR_V_up, tmp_I_up_leak, 1, tmp_B1, 1, tmp_B1, 1);
397  Vmath::Svtvp(n, -JSR_V_up, tmp_I_up, 1, tmp_B1, 1, tmp_B1, 1);
398  Vmath::Svtvp(n, JSR_V_rel, tmp_I_rel, 1, tmp_B1, 1, tmp_B1, 1);
399  Vmath::Smul(n, 1.0 / V_i, tmp_B1, 1, tmp_B1, 1);
400 
401  // B2
402  Array<OneD, NekDouble> &tmp_B2 = outarray[10];
403  Vmath::Sadd(n, Km_Cmdn, inarray[17], 1, tmp_B2, 1);
404  Vmath::Vmul(n, tmp_B2, 1, tmp_B2, 1, tmp_B2, 1);
405  Vmath::Sdiv(n, Cmdn_max * Km_Cmdn, tmp_B2, 1, tmp_B2, 1);
406  Vmath::Sadd(n, Km_Trpn, inarray[17], 1, tmp, 1);
407  Vmath::Vmul(n, tmp, 1, tmp, 1, tmp, 1);
408  Vmath::Sdiv(n, Trpn_max * Km_Trpn, tmp, 1, tmp, 1);
409  Vmath::Vadd(n, tmp, 1, tmp_B2, 1, tmp_B2, 1);
410  Vmath::Sadd(n, 1.0, tmp_B2, 1, tmp_B2, 1);
411 
412  // Calcium concentration (18)
413  Vmath::Vdiv(n, tmp_B1, 1, tmp_B2, 1, outarray[17], 1);
414 
415  // Calcium up (21)
416  Vmath::Vsub(n, tmp_I_up, 1, tmp_I_up_leak, 1, outarray[20], 1);
417  Vmath::Svtvp(n, -JSR_V_rel / JSR_V_up, tmp_I_tr, 1, outarray[20], 1,
418  outarray[20], 1);
419 
420  // Calcium rel (20)
421  Vmath::Vsub(n, tmp_I_tr, 1, tmp_I_rel, 1, tmp, 1);
422  Vmath::Sadd(n, Km_Csqn, inarray[19], 1, outarray[19], 1);
423  Vmath::Vmul(n, outarray[19], 1, outarray[19], 1, outarray[19], 1);
424  Vmath::Sdiv(n, Csqn_max * Km_Csqn, outarray[19], 1, outarray[19], 1);
425  Vmath::Sadd(n, 1.0, outarray[19], 1, outarray[19], 1);
426  Vmath::Vdiv(n, tmp, 1, outarray[19], 1, outarray[19], 1);
427 
428  // Process gating variables
429  const NekDouble *v;
430  const NekDouble *x;
431  NekDouble *x_tau;
432  NekDouble *x_new;
433  // m
434  for (i = 0, v = &inarray[0][0], x = &inarray[1][0], x_new = &outarray[1][0],
435  x_tau = &m_gates_tau[0][0];
436  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
437  {
438  alpha = (*v == (-47.13)) ? 3.2
439  : (0.32 * (*v + 47.13)) /
440  (1.0 - exp((-0.1) * (*v + 47.13)));
441  beta = 0.08 * exp(-(*v) / 11.0);
442  *x_tau = 1.0 / (alpha + beta);
443  *x_new = alpha * (*x_tau);
444  }
445  // h
446  for (i = 0, v = &inarray[0][0], x = &inarray[2][0], x_new = &outarray[2][0],
447  x_tau = &m_gates_tau[1][0];
448  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
449  {
450  alpha = (*v >= -40.0) ? 0.0 : 0.135 * exp(-((*v) + 80.0) / 6.8);
451  beta = (*v >= -40.0)
452  ? 1.0 / (0.13 * (1.0 + exp(-(*v + 10.66) / 11.1)))
453  : 3.56 * exp(0.079 * (*v)) + 310000.0 * exp(0.35 * (*v));
454  *x_tau = 1.0 / (alpha + beta);
455  *x_new = alpha * (*x_tau);
456  }
457  // j
458  for (i = 0, v = &inarray[0][0], x = &inarray[3][0], x_new = &outarray[3][0],
459  x_tau = &m_gates_tau[2][0];
460  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
461  {
462  alpha =
463  (*v >= -40.0)
464  ? 0.0
465  : (-127140.0 * exp(0.2444 * (*v)) -
466  3.474e-05 * exp(-0.04391 * (*v))) *
467  (((*v) + 37.78) / (1.0 + exp(0.311 * ((*v) + 79.23))));
468  beta = (*v >= -40.0) ? (0.3 * exp(-2.535e-07 * (*v)) /
469  (1.0 + exp(-0.1 * (*v + 32.0))))
470  : 0.1212 * exp(-0.01052 * (*v)) /
471  (1.0 + exp(-0.1378 * (*v + 40.14)));
472  *x_tau = 1.0 / (alpha + beta);
473  *x_new = alpha * (*x_tau);
474  }
475  // oa
476  for (i = 0, v = &inarray[0][0], x = &inarray[4][0], x_new = &outarray[4][0],
477  x_tau = &m_gates_tau[3][0];
478  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
479  {
480  alpha = 0.65 / (exp(-(*v + 10.0) / 8.5) + exp(-(*v - 30.0) / 59.0));
481  beta = 0.65 / (2.5 + exp((*v + 82.0) / 17.0));
482  *x_tau = 1.0 / K_Q10 / (alpha + beta);
483  *x_new = (1.0 / (1.0 + exp(-(*v + 20.47) / 17.54)));
484  }
485  // oi
486  for (i = 0, v = &inarray[0][0], x = &inarray[5][0], x_new = &outarray[5][0],
487  x_tau = &m_gates_tau[4][0];
488  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
489  {
490  alpha = 1.0 / (18.53 + exp((*v + 113.7) / 10.95));
491  beta = 1.0 / (35.56 + exp(-(*v + 1.26) / 7.44));
492  *x_tau = 1.0 / K_Q10 / (alpha + beta);
493  *x_new = (1.0 / (1.0 + exp((*v + 43.1) / 5.3)));
494  }
495  // ua
496  for (i = 0, v = &inarray[0][0], x = &inarray[6][0], x_new = &outarray[6][0],
497  x_tau = &m_gates_tau[5][0];
498  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
499  {
500  alpha = 0.65 / (exp(-(*v + 10.0) / 8.5) + exp(-(*v - 30.0) / 59.0));
501  beta = 0.65 / (2.5 + exp((*v + 82.0) / 17.0));
502  *x_tau = 1.0 / K_Q10 / (alpha + beta);
503  *x_new = 1.0 / (1.0 + exp(-(*v + 30.3) / 9.6));
504  }
505  // ui
506  for (i = 0, v = &inarray[0][0], x = &inarray[7][0], x_new = &outarray[7][0],
507  x_tau = &m_gates_tau[6][0];
508  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
509  {
510  alpha = 1.0 / (21.0 + exp(-(*v - 185.0) / 28.0));
511  beta = exp((*v - 158.0) / 16.0);
512  *x_tau = 1.0 / K_Q10 / (alpha + beta);
513  *x_new = 1.0 / (1.0 + exp((*v - 99.45) / 27.48));
514  }
515  // xr
516  for (i = 0, v = &inarray[0][0], x = &inarray[8][0], x_new = &outarray[8][0],
517  x_tau = &m_gates_tau[7][0];
518  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
519  {
520  alpha = 0.0003 * (*v + 14.1) / (1 - exp(-(*v + 14.1) / 5.0));
521  beta = 7.3898e-5 * (*v - 3.3328) / (exp((*v - 3.3328) / 5.1237) - 1.0);
522  *x_tau = 1.0 / (alpha + beta);
523  *x_new = 1.0 / (1 + exp(-(*v + 14.1) / 6.5));
524  }
525  // xs
526  for (i = 0, v = &inarray[0][0], x = &inarray[9][0], x_new = &outarray[9][0],
527  x_tau = &m_gates_tau[8][0];
528  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
529  {
530  alpha = 4e-5 * (*v - 19.9) / (1.0 - exp(-(*v - 19.9) / 17.0));
531  beta = 3.5e-5 * (*v - 19.9) / (exp((*v - 19.9) / 9.0) - 1.0);
532  *x_tau = 0.5 / (alpha + beta);
533  *x_new = 1.0 / sqrt(1.0 + exp(-(*v - 19.9) / 12.7));
534  }
535  // d
536  for (i = 0, v = &inarray[0][0], x = &inarray[10][0],
537  x_new = &outarray[10][0], x_tau = &m_gates_tau[9][0];
538  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
539  {
540  *x_tau = (1 - exp(-(*v + 10.0) / 6.24)) /
541  (0.035 * (*v + 10.0) * (1 + exp(-(*v + 10.0) / 6.24)));
542  *x_new = 1.0 / (1.0 + exp(-(*v + 10) / 8.0));
543  }
544  // f
545  for (i = 0, v = &inarray[0][0], x = &inarray[11][0],
546  x_new = &outarray[11][0], x_tau = &m_gates_tau[10][0];
547  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
548  {
549  // alpha = 1.0/(1.0 + exp((*v+28.0)/6.9));
550  *x_tau =
551  9.0 /
552  (0.0197 * exp(-0.0337 * 0.0337 * (*v + 10.0) * (*v + 10.0)) + 0.02);
553  *x_new = exp((-(*v + 28.0)) / 6.9) / (1.0 + exp((-(*v + 28.0)) / 6.9));
554  }
555  // f_Ca
556  for (i = 0, v = &inarray[0][0], x = &inarray[12][0],
557  x_new = &outarray[12][0], x_tau = &m_gates_tau[11][0];
558  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
559  {
560  *x_tau = 2.0;
561  *x_new = 1.0 / (1.0 + inarray[17][i] / 0.00035);
562  }
563 
564  Array<OneD, NekDouble> &tmp_Fn = outarray[15];
565  Vmath::Svtsvtp(n, 0.5 * 5e-13 / F, tmp_I_Ca_L, 1, -0.2 * 5e-13 / F,
566  tmp_I_Na_Ca, 1, tmp_Fn, 1);
567  Vmath::Svtvm(n, 1e-12 * JSR_V_rel, tmp_I_rel, 1, tmp_Fn, 1, tmp_Fn, 1);
568 
569  // u
570  for (i = 0, v = &tmp_Fn[0], x = &inarray[13][0], x_new = &outarray[13][0],
571  x_tau = &m_gates_tau[12][0];
572  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
573  {
574  *x_tau = 8.0;
575  *x_new = 1.0 / (1.0 + exp(-(*v - 3.4175e-13) / 1.367e-15));
576  }
577  // v
578  for (i = 0, v = &tmp_Fn[0], x = &inarray[14][0], x_new = &outarray[14][0],
579  x_tau = &m_gates_tau[13][0];
580  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
581  {
582  *x_tau = 1.91 + 2.09 / (1.0 + exp(-(*v - 3.4175e-13) / 13.67e-16));
583  *x_new = 1.0 - 1.0 / (1.0 + exp(-(*v - 6.835e-14) / 13.67e-16));
584  }
585  // w
586  for (i = 0, v = &inarray[0][0], x = &inarray[15][0],
587  x_new = &outarray[15][0], x_tau = &m_gates_tau[14][0];
588  i < n; ++i, ++v, ++x, ++x_new, ++x_tau)
589  {
590  *x_tau = 6.0 * (1.0 - exp(-(*v - 7.9) / 5.0)) /
591  (1.0 + 0.3 * exp(-(*v - 7.9) / 5.0)) / (*v - 7.9);
592  *x_new = 1.0 - 1.0 / (1.0 + exp(-(*v - 40.0) / 17.0));
593  }
594 }
595 
596 /**
597  *
598  */
600 {
601  SolverUtils::AddSummaryItem(s, "Cell model", "CourtemancheRamirezNattel98");
602  SolverUtils::AddSummaryItem(s, "Cell model var.", lookupIds[model_variant]);
603 }
604 
606 {
607  Vmath::Fill(m_nq, -81.0, m_cellSol[0], 1);
608  Vmath::Fill(m_nq, 2.908e-03, m_cellSol[1], 1);
609  Vmath::Fill(m_nq, 9.649e-01, m_cellSol[2], 1);
610  Vmath::Fill(m_nq, 9.775e-01, m_cellSol[3], 1);
611  Vmath::Fill(m_nq, 3.043e-02, m_cellSol[4], 1);
612  Vmath::Fill(m_nq, 9.992e-01, m_cellSol[5], 1);
613  Vmath::Fill(m_nq, 4.966e-03, m_cellSol[6], 1);
614  Vmath::Fill(m_nq, 9.986e-01, m_cellSol[7], 1);
615  Vmath::Fill(m_nq, 3.296e-05, m_cellSol[8], 1);
616  Vmath::Fill(m_nq, 1.869e-02, m_cellSol[9], 1);
617  Vmath::Fill(m_nq, 1.367e-04, m_cellSol[10], 1);
618  Vmath::Fill(m_nq, 9.996e-01, m_cellSol[11], 1);
619  Vmath::Fill(m_nq, 7.755e-01, m_cellSol[12], 1);
620  Vmath::Fill(m_nq, 2.35e-112, m_cellSol[13], 1);
621  Vmath::Fill(m_nq, 1.0, m_cellSol[14], 1);
622  Vmath::Fill(m_nq, 0.9992, m_cellSol[15], 1);
623  Vmath::Fill(m_nq, 1.117e+01, m_cellSol[16], 1);
624  Vmath::Fill(m_nq, 1.013e-04, m_cellSol[17], 1);
625  Vmath::Fill(m_nq, 1.39e+02, m_cellSol[18], 1);
626  Vmath::Fill(m_nq, 1.488, m_cellSol[19], 1);
627  Vmath::Fill(m_nq, 1.488, m_cellSol[20], 1);
628 }
629 
631 {
632  switch (idx)
633  {
634  case 0:
635  return "u";
636  case 1:
637  return "m";
638  case 2:
639  return "h";
640  case 3:
641  return "j";
642  case 4:
643  return "o_a";
644  case 5:
645  return "o_i";
646  case 6:
647  return "u_a";
648  case 7:
649  return "u_i";
650  case 8:
651  return "x_r";
652  case 9:
653  return "x_s";
654  case 10:
655  return "d";
656  case 11:
657  return "f";
658  case 12:
659  return "f_Ca";
660  case 13:
661  return "U";
662  case 14:
663  return "V";
664  case 15:
665  return "W";
666  case 16:
667  return "Na_i";
668  case 17:
669  return "Ca_i";
670  case 18:
671  return "K_i";
672  case 19:
673  return "Ca_rel";
674  case 20:
675  return "Ca_up";
676  default:
677  return "unknown";
678  }
679 }
680 
681 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
Cell model base class.
Definition: CellModel.h:66
Array< OneD, Array< OneD, NekDouble > > m_cellSol
Cell model solution variables.
Definition: CellModel.h:126
std::vector< int > m_concentrations
Indices of cell model variables which are concentrations.
Definition: CellModel.h:139
std::vector< int > m_gates
Indices of cell model variables which are gates.
Definition: CellModel.h:141
size_t m_nq
Number of physical points.
Definition: CellModel.h:117
size_t m_nvar
Number of variables in cell model (inc. transmembrane voltage)
Definition: CellModel.h:119
Array< OneD, Array< OneD, NekDouble > > m_gates_tau
Storage for gate tau values.
Definition: CellModel.h:143
virtual void v_GenerateSummary(SummaryList &s) override
Prints a summary of the model parameters.
virtual void v_Update(const Array< OneD, const Array< OneD, NekDouble >> &inarray, Array< OneD, Array< OneD, NekDouble >> &outarray, const NekDouble time) override
Computes the reaction terms $f(u,v)$ and $g(u,v)$.
virtual std::string v_GetCellVarName(size_t idx) override
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
std::shared_ptr< SessionReader > SessionReaderSharedPtr
@ beta
Gauss Radau pinned at x=-1,.
Definition: PointsType.h:61
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
std::vector< std::pair< std::string, std::string > > SummaryList
Definition: Misc.h:48
void AddSummaryItem(SummaryList &l, const std::string &name, const std::string &value)
Adds a summary item to the summary info list.
Definition: Misc.cpp:49
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
CellModelFactory & GetCellModelFactory()
Definition: CellModel.cpp:46
double NekDouble
void Svtsvtp(int n, const T alpha, const T *x, int incx, const T beta, const T *y, int incy, T *z, int incz)
svtvvtp (scalar times vector plus scalar times vector):
Definition: Vmath.cpp:751
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition: Vmath.cpp:209
void Vlog(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.hpp:114
void Vexp(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.hpp:125
void Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
svtvp (scalar times vector plus vector): z = alpha*x + y
Definition: Vmath.cpp:622
void Svtvm(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
svtvp (scalar times vector minus vector): z = alpha*x - y
Definition: Vmath.cpp:664
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition: Vmath.cpp:359
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
Definition: Vmath.cpp:248
void Sdiv(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha/y.
Definition: Vmath.cpp:324
void Vdiv(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x/y.
Definition: Vmath.cpp:284
void Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:492
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition: Vmath.cpp:45
void Sadd(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Add scalar y = alpha + x.
Definition: Vmath.cpp:384
void Vsub(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Subtract vector z = x-y.
Definition: Vmath.cpp:419
void Vpow(int n, const T *x, const int incx, const T f, T *y, const int incy)
Definition: Vmath.hpp:136
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294