MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
NMDAChan.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 ** This program is part of 'MOOSE', the
3 ** Messaging Object Oriented Simulation Environment.
4 ** Copyright (C) 2003-2007 Upinder S. Bhalla. and NCBS
5 ** It is made available under the terms of the
6 ** GNU Lesser General Public License version 2.1
7 ** See the file COPYING.LIB for the full notice.
8 **********************************************************************/
9 
10 #include "header.h"
11 #include "ElementValueFinfo.h"
12 #include "ChanBase.h"
13 #include "ChanCommon.h"
14 #include "SynChan.h"
15 #include "NMDAChan.h"
16 
17 const double EPSILON = 1.0e-12;
18 const double NMDAChan::valency_ = 2.0;
19 
21 {
22  static SrcFinfo1< double > ICaOut( "ICaOut",
23  "Calcium current portion of the total current carried by the NMDAR" );
24  return &ICaOut;
25 }
26 
28 {
30  // Shared messages
33  // Dest definitions
36  // Field definitions
38  static ValueFinfo< NMDAChan, double > KMg_A( "KMg_A",
39  "1/eta",
42  );
43  static ValueFinfo< NMDAChan, double > KMg_B( "KMg_B",
44  "1/gamma",
47  );
48  static ValueFinfo< NMDAChan, double > CMg( "CMg",
49  "[Mg] in mM",
52  );
53  static ValueFinfo< NMDAChan, double > temperature( "temperature",
54  "Temperature in degrees Kelvin.",
57  );
58  static ValueFinfo< NMDAChan, double > extCa( "extCa",
59  "External concentration of Calcium in millimolar",
62  );
63  static ValueFinfo< NMDAChan, double > intCa( "intCa",
64  "Internal concentration of Calcium in millimolar."
65  "This is the final value used by the internal calculations, "
66  "and may also be updated by the assignIntCa message after "
67  "offset and scaling.",
70  );
71  static ValueFinfo< NMDAChan, double > intCaScale( "intCaScale",
72  "Scale factor for internal concentration of Calcium in mM, "
73  "applied to values coming in through the assignIntCa message. "
74  "Required because in many models the units of calcium may "
75  "differ. ",
78  );
79  static ValueFinfo< NMDAChan, double > intCaOffset( "intCaOffset",
80  "Offsetfor internal concentration of Calcium in mM, "
81  "applied _after_ the scaling to mM is done. "
82  "Applied to values coming in through the assignIntCa message. "
83  "Required because in many models the units of calcium may "
84  "differ. ",
87  );
88  static ValueFinfo< NMDAChan, double > condFraction( "condFraction",
89  "Fraction of total channel conductance that is due to the "
90  "passage of Ca ions. This is related to the ratio of "
91  "permeabilities of different ions, and is typically in "
92  "the range of 0.02. This small fraction is largely because "
93  "the concentrations of Na and K ions are far larger than that "
94  "of Ca. Thus, even though the channel is more permeable to "
95  "Ca, the conductivity and hence current due to Ca is smaller. ",
98  );
100  "Current carried by Ca ions",
102  );
104  "permeability",
105  "Permeability. Alias for Gbar. Note that the mapping is not"
106  " really correct. Permeability is in units of m/s whereas "
107  "Gbar is 1/ohm. Some nasty scaling is involved in the "
108  "conversion, some of which itself involves concentration "
109  "variables. Done internally. ",
112  );
114  static DestFinfo assignIntCa( "assignIntCa",
115  "Assign the internal concentration of Ca. The final value "
116  "is computed as: "
117  " intCa = assignIntCa * intCaScale + intCaOffset ",
119  );
121  static Finfo* NMDAChanFinfos[] =
122  {
123  &KMg_A, // Value
124  &KMg_B, // Value
125  &CMg, // Value
126  &temperature, // Value
127  &extCa, // Value
128  &intCa, // Value
129  &intCaScale, // Value
130  &intCaOffset, // Value
131  &condFraction, // Value
132  &ICa, // ReadOnlyValue
133  &permeability, // ElementValue
134  &assignIntCa, // Dest
135  ICaOut(), // Src
136  };
137 
138  static string doc[] =
139  {
140  "Name", "NMDAChan",
141  "Author", "Upinder S. Bhalla, 2007, NCBS",
142  "Description", "NMDAChan: Ligand-gated ion channel incorporating "
143  "both the Mg block and a GHK calculation for Calcium "
144  "component of the current carried by the channel. "
145  "Assumes a steady reversal potential regardless of "
146  "Ca gradients. "
147  "Derived from SynChan. "
148  };
149  static Dinfo< NMDAChan > dinfo;
150  static Cinfo NMDAChanCinfo(
151  "NMDAChan",
153  NMDAChanFinfos,
154  sizeof( NMDAChanFinfos )/sizeof(Finfo *),
155  &dinfo,
156  doc,
157  sizeof( doc ) / sizeof( string )
158  );
159 
160  return &NMDAChanCinfo;
161 }
162 
164 
166 // Constructor
169  :
170  KMg_A_( 1.0 ), // These are NOT the same as the A, B state
171  KMg_B_( 1.0 ), //. variables used for Exp Euler integration.
172  CMg_( 1.0 ),
173  temperature_( 300 ),
174  Cout_( 1.5 ),
175  Cin_( 0.0008 ),
176  intCaScale_( 1.0 ),
177  intCaOffset_( 0.0 ),
178  condFraction_( 0.02 ),
179  ICa_( 0.0 ),
180  const_( FaradayConst * valency_ / (GasConst * temperature_ ) )
181 {;}
182 
184 {;}
185 
187 // Field function definitions
189 
190 void NMDAChan::setKMg_A( double KMg_A )
191 {
192  if ( KMg_A < EPSILON ) {
193  cout << "Error: KMg_A=" << KMg_A << " must be > 0. Not set.\n";
194  } else {
195  KMg_A_ = KMg_A;
196  }
197 }
198 double NMDAChan::getKMg_A() const
199 {
200  return KMg_A_;
201 }
202 void NMDAChan::setKMg_B( double KMg_B )
203 {
204  if ( KMg_B < EPSILON ) {
205  cout << "Error: KMg_B=" << KMg_B << " must be > 0. Not set.\n";
206  } else {
207  KMg_B_ = KMg_B;
208  }
209 }
210 double NMDAChan::getKMg_B() const
211 {
212  return KMg_B_;
213 }
214 void NMDAChan::setCMg( double CMg )
215 {
216  if ( CMg < EPSILON ) {
217  cout << "Error: CMg = " << CMg << " must be > 0. Not set.\n";
218  } else {
219  CMg_ = CMg;
220  }
221 }
222 double NMDAChan::getCMg() const
223 {
224  return CMg_;
225 }
226 
227 void NMDAChan::setExtCa( double Cout )
228 {
229  if ( Cout < EPSILON ) {
230  cout << "Error: Cout = " << Cout << " must be > 0. Not set.\n";
231  } else {
232  Cout_ = Cout;
233  }
234 }
235 double NMDAChan::getExtCa() const
236 {
237  return Cout_;
238 }
239 
240 void NMDAChan::setIntCa( double Cin )
241 {
242  if ( Cin < 0.0 ) {
243  cout << "Error: IntCa = " << Cin << " must be > 0. Not set.\n";
244  } else {
245  Cin_ = Cin;
246  }
247 }
248 
249 double NMDAChan::getIntCa() const
250 {
251  return Cin_;
252 }
253 
254 void NMDAChan::setIntCaScale( double v )
255 {
256  intCaScale_ = v;
257 }
258 
260 {
261  return intCaScale_;
262 }
263 
264 void NMDAChan::setIntCaOffset( double v )
265 {
266  intCaOffset_ = v;
267 }
268 
270 {
271  return intCaOffset_;
272 }
273 
275 {
276  condFraction_ = v;
277 }
278 
280 {
281  return condFraction_;
282 }
283 
284 double NMDAChan::getICa() const
285 {
286  return ICa_;
287 }
288 
290 {
291  return temperature_;
292 }
293 void NMDAChan::setTemperature( double temperature )
294 {
295  if ( temperature < EPSILON ) {
296  cout << "Error: temperature = " << temperature << " must be > 0. Not set.\n";
297  return;
298  }
299  temperature_ = temperature;
301 }
302 
304 // MsgDest function
306 void NMDAChan::assignIntCa( double v )
307 {
308  Cin_ = v * intCaScale_ + intCaOffset_;
309 }
310 
326 // Process functions
329 
331 {
332  // First do the regular channel current calculations for the
333  // summed ions, in which the NMDAR behaves like a regular channel
334  // modulo the Mg block.
335  double Gk = SynChan::calcGk();
336  double KMg = KMg_A_ * exp(Vm_/KMg_B_);
337  Gk *= KMg / (KMg + CMg_);
338  ChanBase::setGk( e, Gk );
340 
342  // Here we do the calculations for the Ca portion of the current.
343  // Total current is still done using a regular reversal potl for chan.
344  // Here we use Gk = Permeability * Z * FaradayConst * area / dV.
345  // Note that Cin and Cout are in moles/m^3, and FaradayConst is in
346  // Coulombs/mole.
347  //
348  // The GHK flux equation for an ion S (Hille 2001):
349  // \Phi_{S} = P_{S}z_{S}^2\frac{V_{m}F^{2}}{RT}\frac{[\mbox{S}]_{i} - [\mbox{S}]_{o}\exp(-z_{S}V_{m}F/RT)}{1 - \exp(-z_{S}V_{m}F/RT)}
350  // where
351  // \PhiS is the current across the membrane carried by ion S, measured in amperes per square meter (A·m−2)
352  // PS is the permeability of the membrane for ion S measured in m·s−1
353  // zS is the valence of ion S
354  // Vm is the transmembrane potential in volts
355  // F is the Faraday constant, equal to 96,485 C·mol−1 or J·V−1·mol−1
356  // R is the gas constant, equal to 8.314 J·K−1·mol−1
357  // T is the absolute temperature, measured in Kelvin (= degrees Celsius + 273.15)
358  // [S]i is the intracellular concentration of ion S, measured in mol·m−3 or mmol·l−1
359  // [S]o is the extracellular concentration of ion S, measured in mol·m−3
360  //
361  // Put this into cleaner text, we get
362  //
363  // ICa (A/m^2) = perm * Z * Vm * F * const * (Cin-Cout * e2exponent)
364  // ----------------------
365  // (1-e2exponent)
366  //
367  // where const = zF/RT (Coulombs/J/K * K ) = Coul/J = 1/V
368  // and exponent = const * Vm ( unitless)
369  //
370  // We want ICa in Amps. We use perm times area which is m^3/s
371  // Flux ( mol/sec) = Perm (m/s ) * area (m^2) * (Cout - Cin) (mol/m^3)
372  //
373  // But we also have
374  //
375  // Flux (mol/sec) = Gk ( Coul/(sec*V) ) * dV (V) / (zF (Coul/Mol))
376  //
377  // So Perm( m/s ) * Area = Gk * dV / (Z*F * (cout - cin) )
378  //
379  // Note that dV should be just the Nernst potential for the ion, since
380  // the calculation of flux from permeability assumes no extra flux
381  // due to charge gradients.
382  //
383  // e2exponent = exp( -const * Vm)
384  //
385  // ICa (A) = (Gk * dV / (zF*(cout-cin) ) * Vm * zF * const * (Cin-Cout * e2exponent)
386  // ----------------------
387  // (1-e2exponent)
388  //
389  // = Gk * dV * Vm * const*(cin - cout*e2exponent)
390  // ------------------------------
391  // (cout-cin) * (1-e2exponent)
392  //
393  // Note how the calculation for Perm in terms of Gk has to use
394  // different terms for dV and conc, than the GHK portion.
395  //
396  // A further factor comes in because we want to relate the Gk for
397  // Ca to that for the channel as a whole. We know from Hille that
398  // the permeability of NMDAR for Ca is about 4x that for Na.
399  //
400  // Here is the calculation:
401  // Gchan = GNa + GK + GCa (Eq1)
402  // IChan = 0 = GNa*ENa + GK*EK + GCa*ECa (Eq2)
403  //
404  // Perm_Ca * area = GCa * ECa / ( ZF * (cout - cin ) ) (Eq3a)
405  // Perm_Na * area = GNa * ENa / ( ZF * (cout - cin ) ) (Eq3b)
406  // But Perm_Na ~ 0.25 * perm_Ca
407  // So GNa*ENa / (F * (cout - cin ) ) ~ 0.25*GCa*ECa/(2F*(cout-cin) )
408  // Cancelling
409  //
410  // GNa * 0.060 / (cout - cin|Na) ~ 0.25*GCa*0.128/(2*(cout-cin|Ca))
411  // GNa * 0.060 / 130 ~ GCa * 0.25 * 0.128 / (2*1.5)
412  // GNa ~ GCa * 130 * 0.25 * 0.128 / ( 2 * 1.5 * 0.060)
413  // GNa ~ 23 GCa (!!!!!!) (Eq4)
414  //
415  // Now plug into Eq2:
416  //
417  // 0 = 23GCa*0.06 - GK*0.08 + GCa*0.128
418  // So
419  // GK = GCa(0.06*23 + 0.128) / 0.06 = 25*GCa. (Not surprised any more)
420  //
421  // Finally, put into Eq1:
422  //
423  // Gchan = 23GCa + 25GCa + GCa
424  // So GCa = Gchan / 49. So condFraction ~0.02 in the vicinity of 0.0mV.
425  //
426  // Rather than build in this calculation, I'll just provide the user
427  // with a scaling field to use and set it to the default of 0.02
428  //
429  double ErevCa = log( Cout_ / Cin_ ) / const_;
430  double dV = ErevCa;
431  //double dV = ErevCa - Vm_;
432  // double dV = vGetEk( e ) - Vm_;
433  // double dV = Vm_;
434  double exponent = const_ * Vm_;
435  double e2e = exp( -exponent );
436  if ( fabs( exponent) < 0.00001 ) { // Exponent too near zero, use Taylor
437  ICa_ = Gk * dV * exponent * ( Cin_ - Cout_ * e2e ) /
438  ( ( Cin_ - Cout_ ) * (1 - 0.5 * exponent ) );
439  } else {
440  ICa_ = Gk * dV * exponent * ( Cin_ - Cout_ * e2e ) /
441  ( ( Cin_ - Cout_ ) * (1 - e2e ) );
442  }
443  ICa_ *= condFraction_; // Scale Ca current by fraction carried by Ca.
444 
445  sendProcessMsgs( e, info );
446  ICaOut()->send( e, ICa_ );
447 }
448 
450 {
451  SynChan::vReinit( e, info );
452  if ( CMg_ < EPSILON || KMg_B_ < EPSILON || KMg_A_ < EPSILON ) {
453  cout << "Error: NMDAChan::innerReinitFunc: fields KMg_A, KMg_B, CMg\nmust be greater than zero. Resetting to 1 to avoid numerical errors\n";
454  if ( CMg_ < EPSILON ) CMg_ = 1.0;
455  if ( KMg_B_ < EPSILON ) KMg_B_ = 1.0;
456  if ( KMg_A_ < EPSILON ) KMg_A_ = 1.0;
457  }
458  sendReinitMsgs( e, info );
459  ICaOut()->send( e, 0.0 );
460 }
461 
463 // Unit tests
465 
static const Cinfo * initCinfo()
Definition: SynChan.cpp:20
void setIntCaOffset(double v)
Definition: NMDAChan.cpp:264
void setCondFraction(double v)
Definition: NMDAChan.cpp:274
void vReinit(const Eref &e, ProcPtr p)
Definition: NMDAChan.cpp:449
double condFraction_
Definition: NMDAChan.h:82
Definition: Dinfo.h:60
double intCaOffset_
Definition: NMDAChan.h:81
static const Cinfo * initCinfo()
Definition: NMDAChan.cpp:27
double getIntCaOffset() const
Definition: NMDAChan.cpp:269
double getTemperature() const
Definition: NMDAChan.cpp:289
double getExtCa() const
Set external conc.
Definition: NMDAChan.cpp:235
const double FaradayConst
Definition: consts.cpp:17
SrcFinfo1< double > * ICaOut()
Definition: NMDAChan.cpp:20
void updateIk()
Definition: ChanCommon.cpp:119
const double EPSILON
Definition: NMDAChan.cpp:17
double getKMg_A() const
Definition: NMDAChan.cpp:198
double intCaScale_
Definition: NMDAChan.h:80
double getCMg() const
Definition: NMDAChan.cpp:222
void setExtCa(double conc)
Definition: NMDAChan.cpp:227
void log(string msg, serverity_level_ type=debug, bool redirectToConsole=true, bool removeTicks=true)
Log to console (and to a log-file)
void setKMg_B(double Ek)
Definition: NMDAChan.cpp:202
double temperature_
Definition: NMDAChan.h:77
void setGk(const Eref &e, double Gk)
Definition: ChanBase.cpp:216
static SrcFinfo1< double > * permeability()
Definition: ChanBase.cpp:14
double getCondFraction() const
Definition: NMDAChan.cpp:279
void setIntCaScale(double v)
Definition: NMDAChan.cpp:254
const double GasConst
Definition: consts.cpp:19
double getIntCaScale() const
Definition: NMDAChan.cpp:259
double Vm_
Vm_ is input variable from compartment, used for most rates.
Definition: ChanCommon.h:80
double getICa() const
Definition: NMDAChan.cpp:284
Definition: OpFunc.h:27
Definition: Eref.h:26
double Cout_
Definition: NMDAChan.h:78
double calcGk()
Update alpha function terms for synaptic channel.
Definition: SynChan.cpp:200
void assignIntCa(double v)
Definition: NMDAChan.cpp:306
void setIntCa(double conc)
Definition: NMDAChan.cpp:240
void setCMg(double CMg)
Definition: NMDAChan.cpp:214
void setKMg_A(double Gbar)
Definition: NMDAChan.cpp:190
double getIntCa() const
Set external conc.
Definition: NMDAChan.cpp:249
void sendReinitMsgs(const Eref &e, const ProcPtr info)
Definition: ChanCommon.cpp:111
double CMg_
[Mg] in mM
Definition: NMDAChan.h:72
double Cin_
Definition: NMDAChan.h:79
double ICa_
Definition: NMDAChan.h:83
void setGbar(const Eref &e, double Gbar)
Definition: ChanBase.cpp:185
double const_
Definition: NMDAChan.h:84
double KMg_B_
1/gamma
Definition: NMDAChan.h:70
void vReinit(const Eref &e, ProcPtr p)
Definition: SynChan.cpp:229
static const Cinfo * NMDAChanCinfo
Definition: NMDAChan.cpp:163
double KMg_A_
1/eta
Definition: NMDAChan.h:68
void sendProcessMsgs(const Eref &e, const ProcPtr info)
Definition: ChanCommon.cpp:100
double getGbar(const Eref &e) const
Definition: ChanBase.cpp:191
static const double valency_
Definition: NMDAChan.h:87
Definition: Cinfo.h:18
void setTemperature(double temperature)
Definition: NMDAChan.cpp:293
void vProcess(const Eref &e, ProcPtr p)
Definition: NMDAChan.cpp:330
Definition: Finfo.h:12
double getKMg_B() const
Definition: NMDAChan.cpp:210