Xyce  6.1
N_DEV_Neuron6.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2015 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-----------------------------------------------------------------------------
24 
25 //-------------------------------------------------------------------------
26 // Filename : $RCSfile: N_DEV_Neuron6.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Richard Schiek, Electrical and Microsytem Modeling
33 //
34 // Creation Date : 06/10/09
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.70.2.1 $
40 //
41 // Revision Date : $Date: 2015/04/02 18:29:38 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 
49 // ---------- Standard Includes ----------
50 
51 
52 // ---------- Xyce Includes ----------
53 #include <N_DEV_DeviceOptions.h>
54 #include <N_DEV_DeviceMaster.h>
55 #include <N_DEV_ExternData.h>
56 #include <N_DEV_MatrixLoadData.h>
57 #include <N_DEV_MembraneCS.h>
58 #include <N_DEV_MembraneHH.h>
59 #include <N_DEV_MembranePassive.h>
61 #include <N_DEV_Neuron6.h>
63 #include <N_DEV_SolverState.h>
64 #include <N_DEV_Message.h>
65 #include <N_ERH_ErrorMgr.h>
66 
67 #include <N_DEV_Neuron.h>
68 
69 #include <N_LAS_Vector.h>
70 #include <N_LAS_Matrix.h>
71 #include <N_UTL_FeatureTest.h>
72 #include <N_UTL_Math.h>
73 
74 namespace Xyce {
75 namespace Device {
76 
77 namespace Neuron6 {
78 
80 {
81  p.addPar ("R",1.0,&Neuron6::Instance::rInt)
82  .setGivenMember(&Neuron6::Instance::rIntGiven)
83  .setUnit(U_OHMM)
84  .setCategory(CAT_NONE)
85  .setDescription("Intracellular resistivity");
86  // typical values 1-3 kOhm-mm; use 1 Kohm-mm which is the same as 1 Ohm-m
87  p.addPar ("A",0.00025,&Neuron6::Instance::radius)
88  .setGivenMember(&Neuron6::Instance::radiusGiven)
89  .setUnit(U_METER)
90  .setCategory(CAT_NONE)
91  .setDescription("Segment radius");
92  // 250 microns,based on NEURON default diameter of 500 microns
93  p.addPar ("L",0.0001,&Neuron6::Instance::length)
94  .setGivenMember(&Neuron6::Instance::lengthGiven)
95  .setUnit(U_METER)
96  .setCategory(CAT_NONE)
97  .setDescription("Cable length");
98  // 100 microns,based on NEURON default length
99 
101  .setGivenMember(&Neuron6::Instance::nSegGiven)
102  .setUnit(U_NONE)
103  .setCategory(CAT_NONE)
104  .setDescription("Number of segments");
105 }
106 
108 {
109  p.addPar ("CMEM",0.0,&Neuron6::Model::cMem)
110  .setGivenMember(&Neuron6::Model::cMemGiven)
111  .setUnit(U_FARADMM2)
112  .setCategory(CAT_NONE)
113  .setDescription("Membrane capacitance");
114 
115  p.addPar ("GMEM",0.0,&Neuron6::Model::gMem)
116  .setGivenMember(&Neuron6::Model::gMemGiven)
117  .setUnit(U_OHMM1MM2)
118  .setCategory(CAT_NONE)
119  .setDescription("Membrane conductance");
120 
121  p.addPar ("VREST",0.0,&Neuron6::Model::vRest)
122  .setGivenMember(&Neuron6::Model::vRestGiven)
123  .setUnit(U_VOLT)
124  .setCategory(CAT_NONE)
125  .setDescription("Resting potential");
126 
127  p.addPar ("EK",0.0,&Neuron6::Model::eK)
128  .setGivenMember(&Neuron6::Model::eKGiven)
129  .setUnit(U_VOLT)
130  .setCategory(CAT_NONE)
131  .setDescription("Potassium resting potential");
132 
133  p.addPar ("GK",0.0,&Neuron6::Model::gK)
134  .setGivenMember(&Neuron6::Model::gKGiven)
135  .setUnit(U_OHMM1MM2)
136  .setCategory(CAT_NONE)
137  .setDescription("Potassium base conductance");
138 
139  p.addPar ("ENA",0.0,&Neuron6::Model::eNa)
140  .setGivenMember(&Neuron6::Model::eNaGiven)
141  .setUnit(U_VOLT)
142  .setCategory(CAT_NONE)
143  .setDescription("Sodium resting potential");
144 
145  p.addPar ("GNA",0.0,&Neuron6::Model::gNa)
146  .setGivenMember(&Neuron6::Model::gNaGiven)
147  .setUnit(U_OHMM1MM2)
148  .setCategory(CAT_NONE)
149  .setDescription("Sodium base conductance");
150 
151  p.addPar ("EA",0.0,&Neuron6::Model::eA)
152  .setGivenMember(&Neuron6::Model::eAGiven)
153  .setUnit(U_VOLT)
154  .setCategory(CAT_NONE)
155  .setDescription("a-current rest potential");
156 
157  p.addPar ("GA",0.0,&Neuron6::Model::gA)
158  .setGivenMember(&Neuron6::Model::gAGiven)
159  .setUnit(U_OHMM1MM2)
160  .setCategory(CAT_NONE)
161  .setDescription("a-current base conductance");
162 
163  p.addPar ("ECA",0.0,&Neuron6::Model::eCa)
164  .setGivenMember(&Neuron6::Model::eCaGiven)
165  .setUnit(U_VOLT)
166  .setCategory(CAT_NONE)
167  .setDescription("Calcium rest potential");
168 
169  p.addPar ("GCA",0.0,&Neuron6::Model::gCa)
170  .setGivenMember(&Neuron6::Model::gCaGiven)
171  .setUnit(U_OHMM1MM2)
172  .setCategory(CAT_NONE)
173  .setDescription("Calcium base conductance");
174 
175  p.addPar ("EKCA",0.0,&Neuron6::Model::eKCa)
176  .setGivenMember(&Neuron6::Model::eKCaGiven)
177  .setUnit(U_VOLT)
178  .setCategory(CAT_NONE)
179  .setDescription("Potassium-calcium rest potential");
180 
181  p.addPar ("GKCA",0.0,&Neuron6::Model::gKCa)
182  .setGivenMember(&Neuron6::Model::gKCaGiven)
183  .setUnit(U_OHMM1MM2)
184  .setCategory(CAT_NONE)
185  .setDescription("Potassium-calcium base conductance");
186 
187  p.addPar ("CAINIT",0.0,&Neuron6::Model::CaInit)
188  .setGivenMember(&Neuron6::Model::CaInitGiven)
189  .setUnit(U_MOLAR)
190  .setCategory(CAT_NONE)
191  .setDescription("initial intra-cellular calcium concentration");
192 
193  p.addPar ("CAGAMMA",0.0,&Neuron6::Model::CaGamma)
194  .setGivenMember(&Neuron6::Model::CaGammaGiven)
195  .setUnit(U_NONE)
196  .setCategory(CAT_NONE)
197  .setDescription("calcium current to concentration multiplier");
198 
199  p.addPar ("CATAU",0.0,&Neuron6::Model::CaTau)
200  .setGivenMember(&Neuron6::Model::CaTauGiven)
201  .setUnit(U_SECOND)
202  .setCategory(CAT_NONE)
203  .setDescription("calcium removal time constant");
204 
205  p.addPar ("R",1.0,&Neuron6::Model::rInt)
206  .setGivenMember(&Neuron6::Model::rIntGiven)
207  .setUnit(U_OHMM)
208  .setCategory(CAT_NONE)
209  .setDescription("Intracellular resistivity");
210  // typical values 1-3 kOhm-mm; use 1 Kohm-mm which is the same as 1 Ohm-m
211 
212  p.addPar ("A",0.00025,&Neuron6::Model::radius)
213  .setGivenMember(&Neuron6::Model::radiusGiven)
214  .setUnit(U_METER)
215  .setCategory(CAT_NONE)
216  .setDescription("Segment radius");
217  // 250 microns,based on NEURON default diameter of 500 microns
218 
219  p.addPar ("L",0.0001,&Neuron6::Model::length)
220  .setGivenMember(&Neuron6::Model::lengthGiven)
221  .setUnit(U_METER)
222  .setCategory(CAT_NONE)
223  .setDescription("Cable length");
224  // 100 microns,based on NEURON default length
225 
226  p.addPar ("I",0.0,&Neuron6::Model::I)
227  .setExpressionAccess(ParameterType::SOLN_DEP)
228  .setUnit(U_AMP)
229  .setCategory(CAT_NONE)
230  .setDescription("Current for user-defined current equation");
231 
232  p.addPar("IONCHANNELMODEL","",&Neuron6::Model::ionChannelModel)
233  .setGivenMember(&Neuron6::Model::ionChannelModelGiven)
234  .setUnit(U_NONE)
235  .setCategory(CAT_NONE)
236  .setDescription("Neuron6::Model to use for ion channels");
237 
238  p.addPar("N",1,&Neuron6::Model::nSeg)
239  .setGivenMember(&Neuron6::Model::nSegGiven)
240  .setUnit(U_NONE)
241  .setCategory(CAT_NONE)
242  .setDescription("Number of segments");
243 
244  p.addPar("MM_CURRENT",std::vector<std::string>(),&Neuron6::Model::membraneCurrentEqus)
246  .setUnit(U_NONE)
247  .setCategory(CAT_NONE)
248  .setDescription("Contribution to membrane current");
249 
250  p.addPar("MM_INDVARS",std::vector<std::string>(),&Neuron6::Model::membraneIndpVars)
251  .setGivenMember(&Neuron6::Model::membraneIndpVarsGiven)
252  .setUnit(U_NONE)
253  .setCategory(CAT_NONE)
254  .setDescription("Independant variables for ion channel equations");
255 
256  p.addPar("MM_INDFEQUS",std::vector<std::string>(),&Neuron6::Model::membraneIndpFEqus)
258  .setUnit(U_NONE)
259  .setCategory(CAT_NONE)
260  .setDescription("Independant variables: F equations");
261 
262  p.addPar("MM_INDQEQUS",std::vector<std::string>(),&Neuron6::Model::membraneIndpQEqus)
264  .setUnit(U_NONE)
265  .setCategory(CAT_NONE)
266  .setDescription("Independant variables: Q equations");
267 
268  p.addPar("MM_FUNCTIONS",std::vector<std::string>(),&Neuron6::Model::membraneFunctions)
270  .setUnit(U_NONE)
271  .setCategory(CAT_NONE)
272  .setDescription("Functions for membrane Neuron6::Model");
273 
274  p.addPar("MM_PARAMETERS",std::vector<std::string>(),&Neuron6::Model::membraneParameters)
276  .setUnit(U_NONE)
277  .setCategory(CAT_NONE)
278  .setDescription("Parameters for membrane Neuron6::Model");
279 }
280 
281 
282 // Class Instance
283 
284 //-----------------------------------------------------------------------------
285 // Function : Instance::Instance
286 // Purpose : constructor
287 // Special Notes :
288 // Scope : public
289 // Creator : Richard Schiek, Electrical and Microsytem Modeling
290 // Creation Date : 06/10/09
291 //-----------------------------------------------------------------------------
293  const Configuration & configuration,
294  const InstanceBlock & IB,
295  Model & Miter,
296  const FactoryBlock & factory_block)
297  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
298  model_(Miter),
299  rInt(0.0),
300  radius(0.0),
301  length(0.0),
302  segArea(0.0),
303  gSeg(0.0),
304  nSeg(0),
305  rIntGiven(false),
306  radiusGiven(false),
307  lengthGiven(false),
308  nSegGiven(false),
309  numIntVarsPerSegment(0),
310  numStateVarsPerSegment(0),
311  kcl1Fvalue(0.0),
312  kcl2Fvalue(0.0),
313  dkcl1F_dVin(0.0),
314  dkcl1F_dVs0(0.0),
315  dkcl2F_dVout(0.0),
316  dkcl2F_dVsn(0.0),
317  li_Pos(0),
318  li_Neg(0),
319  APosEquPosNodeOffset(0),
320  APosEquNextNodeOffset(0),
321  ANegEquNegNodeOffset(0),
322  ANegEquLastNodeOffset(0)
323 {
324  numExtVars = 2; // input and output voltage
325 
326  // Set params to constant default values:
327  setDefaultParams ();
328 
329  // Set params according to instance line
330  setParams (IB.params);
331 
332  // Set any non-constant parameter defaults:
333 
334  //if (!given("TEMP"))
335  // temp = getDeviceOptions().temp.dVal();
336 
337  // Calculate any parameters specified as expressions:
339 
340  // calculate dependent (ie computed) params and check for errors:
341  processParams ();
342 
343  // pull unspecified params out of the model if they weren't specified here
344  if( !nSegGiven && model_.nSegGiven )
345  {
346  nSeg = model_.nSeg;
347  nSegGiven = true;
348  }
349  if( !rIntGiven && model_.rIntGiven )
350  {
351  rInt = model_.rInt;
352  rIntGiven = true;
353  }
354  if( !radiusGiven && model_.radiusGiven )
355  {
356  radius = model_.radius;
357  radiusGiven = true;
358  }
359  if( !lengthGiven && model_.lengthGiven )
360  {
361  length = model_.length;
362  lengthGiven = true;
363  }
364 
365  // if nSeg is still unknown then estimate it via lambda-d rule
366  if (!nSegGiven)
367  {
368  // equations from The Neuron Book, pgs 122-123
369  // says d_lambda value of 0.1 is adequate for most purposes;
370  // use a smaller value if membrane time constant (tau_m) is shorter than 8 ms
371  // but generally uses directly specify nSeg if the default rule doesn't apply
372  double d_lambda = 0.1;
373  double f = 100.0; // frequency
374  // In equations from Neuron book, C was given in uF; we use F
375  double cMem = model_.cMem * 1.0e6;
376  // NEURON version of lambda_f equation took d in microns, other
377  // distances in cm, and returned lambda_f in microns:
378  // lambda_f = 1.0e5 * sqrt(2*radius/(4*M_PI*f*rInt*cMem));
379  // nSeg = int((length/(d_lambda*lambda_f)+0.9)/2)*2 + 1;
380  // I modified the coefficient in the lambda_f equation
381  // to keep distance units in cm
382  // (should also work in other units as long as the units are consistent)
383  double lambda_f = 1.0e3 * sqrt(2*radius/(4*M_PI*f*rInt*cMem));
384  nSeg = int((length/(d_lambda*lambda_f)+0.9)/2)*2 + 1;
385  }
386 
387  // now that nSeg, length and radius are set calculate segment area
388  segArea = 2.0 * M_PI * radius * length / nSeg;
389 
390  // now we can calculate the number of internal vars
391  // by default we'll have a voltage at each node (nSeg)
392  // and no state vars. If the user has an ion channel on, then we'll add in vars for that
393  // ask the membrane model for the number of vars it has.
396 
397  /*
398  if( model_.ConnorStevensOn_ ) {
399  numIntVarsPerSegment += 9;
400  numStateVarsPerSegment += 2; // two currents per segment
401  }
402  */
403 
406 
407  // total up number of vars.
408  int numVars = numExtVars + numIntVars;
409 
410  //
411  // i(n) - I(n)/A - g(n,n+1) * (V(n+1) - V(n)) - g(n,n-1) * (V(n-1) - V(n)) + Cm dV(n)/d(t) = 0 LHS needs leak term memG ( vSeg - vRest )
412  //
413  // Vin : i(n) - I(n)/A - g(n,n+1) * (V(n+1) - V(n)) + Cm dV(n)/d(t) = 0
414  // Vout : i(n) - I(n)/A - g(n,n-1) * (V(n-1) - V(n)) + Cm dV(n)/d(t) = 0
415  // Vnode : i(n) - I(n)/A - g(n,n+1) * (V(n+1) - V(n)) - g(n,n-1) * (V(n-1) - V(n)) + Cm dV(n)/d(t) = 0
416  // plus node supporting equations (a, b, m)
417  //
418  // jacobian format for just the passive cable
419  // Vin Vout V1 V(nSeg)
420  // kcl Vin yes g(0,1)
421  // kcl Vout yes g(n,n-1)
422  // kcl V1 yes yes yes
423  //
424 
425  // if the membrane model includes additional internal variables, the above changes to something
426  // along these lines:
427  // Vin Vout V1 x1 y1 V(nSeg) x(nSeg) y(nSeg)
428  // kcl Vin yes g(0,1)
429  // kcl Vout yes g(n,n-1)
430  // kcl V1 yes yes yes yes yes
431  // note that V1's dependence on internal variables for segment 1 comes before dependence on
432  // Vnext, except for the last segment, in which case Vnext is Vout
433 
434  // set up jacStamp. This is dependant on the membrane model. The only part this
435  // constructor really knows about is the external variables Vin and vOut and internal node
436  // voltages
437 
438  if( jacStamp.empty() ) // redundant as jacStamp is not static for this device
439  { // it can't be as each cable may have a different number of nodes
440  jacStamp.resize(numVars);
441  jacStamp[0].resize(2);
442  jacStamp[0][0] = 0; // Vin
443  jacStamp[0][1] = 2; // Vseg[0]
444  jacStamp[1].resize(2);
445  jacStamp[1][0] = 1; // Vout
446  jacStamp[1][1] = numVars - numIntVarsPerSegment; // VnSeg[nSeg-1]
447 
448  // now loop over each segment and have the membrane model fill that instanceContainer
449  for( int i=0; i<nSeg; i++ )
450  {
451  // the cable model should take care of the Vpre, V, Vnext dependence as that
452  // is part of the cable equation. Let the membraneModel_ handle what happens
453  // at the membrane level
454  int offset = numExtVars + i * numIntVarsPerSegment; // row for vSeg
455  jacStamp[offset].resize( numIntVarsPerSegment + 2 ); // + 2 for Vin and Vout
456 
457  // have to handle a few special cases which can alter the ordering of Vprev, Vseg, Vnext
458  // for each segment number, save the offsets for the previous, current, and next segment so
459  // we don't have to rethink these special cases every time.
460  if( nSeg == 1 )
461  {
462  // here the ordering is Vin Vout Vseg
463  prevMap[i] = 0;
464  nextMap[i] = 1;
465  segMap[i] = 2;
466  jacStamp[offset][prevMap[i]] = 0; // Vin
467  jacStamp[offset][nextMap[i]] = 1; // Vout
468  jacStamp[offset][segMap[i]] = 2; // Vseg
469 
470  }
471  else if( i==0 )
472  {
473  // ordering is Vin Vseg (seg int vars) Vnext
474  prevMap[i] = 0;
475  segMap[i] = 1;
476  nextMap[i] = numIntVarsPerSegment+1;
477  jacStamp[offset][prevMap[i]] = 0; // Vin
478  jacStamp[offset][segMap[i]] = offset; // Vseg
479  jacStamp[offset][nextMap[i]] = offset + numIntVarsPerSegment; // Vnext
480  }
481  else if( i==(nSeg-1) )
482  {
483  // ordering is Vout Vprev Vseg
484  nextMap[i] = 0;
485  prevMap[i] = 1;
486  segMap[i] = 2;
487  jacStamp[offset][nextMap[i]] = 1; // Vout
488  jacStamp[offset][prevMap[i]] = offset - numIntVarsPerSegment; // Vprev
489  jacStamp[offset][segMap[i]] = offset; // Vseg
490  }
491  else
492  {
493  // ordering is Vprev Vseg (seg int vars) Vnext
494  prevMap[i] = 0;
495  segMap[i] = 1;
496  nextMap[i] = numIntVarsPerSegment+1;
497  jacStamp[offset][prevMap[i]] = offset - numIntVarsPerSegment; // Vprev
498  jacStamp[offset][segMap[i]] = offset; // Vseg
499  jacStamp[offset][nextMap[i]] = offset + numIntVarsPerSegment; // Vnext
500  }
501 
502  // pass the membraneModel_ enough information for it to construct its part of the jacobian
503  model_.membraneModel_->setJacStamp( numExtVars, i, segMap[i], jacStamp );
504  }
505 
506  }
507 
508  /*
509  // print out jacStamp
510  Xyce::dout() << "jacStamp for Neuron6" << std::endl;
511  int numRows = jacStamp.size();
512  for( int i=0; i< numRows; i++ )
513  {
514  int numCol = jacStamp[i].size();
515  Xyce::dout() << "jacStamp[ " << i << " ] = { ";
516  for(int j=0; j<numCol; j++)
517  {
518  Xyce::dout() << jacStamp[i][j] << " ";
519  }
520  Xyce::dout() << " } " << std::endl;
521  }
522  Xyce::dout() << std::endl;
523  */
524 
525 
526 
527  // calculate segment conductivities used in load calls:
528  // equation 6.30 Theoretical neuroscience: computational and mathematical modeling of neural systems, Peter Dayan and L. F. Abbot 2001
529  // g(n,n') = radius * (radius')^2 / ( rInt segLength * ( segLength * (radius')^2 + segLength' * (radius)^2 ) )
530  // this equation is in terms of current/area, in which case conductivity to the previous and next
531  // segment is not symmetric if the segment length and/or radius is not are not equal
532  // But since we work in current rather than current density, this is not a problem
533  double segLength = length / nSeg;
534  double rLong = rInt * segLength / (M_PI * radius * radius); // longitudinal resistance (ohm)
535 
536  // watch out for divide-by-0 cases; if resistivity is close to 0, just set conductance to some large value
537  // TODO: Really should be testing for anything close enough to zero to cause problems. Is there a better 'large' value to use?
538  if (rLong == 0.0)
539  {
540  gSeg = 1000.0;
541  }
542  else
543  {
544  gSeg = 1.0 / rLong;
545  }
546 
547  // variable indecies loads
549  {
550  li_Vol.resize(nSeg);
551  li_nPro.resize(nSeg);
552  li_mPro.resize(nSeg);
553  li_hPro.resize(nSeg);
554  li_aPro.resize(nSeg);
555  li_bPro.resize(nSeg);
556  li_MPro.resize(nSeg);
557  li_HPro.resize(nSeg);
558  li_cPro.resize(nSeg);
559  li_CaPro.resize(nSeg);
560  li_KCurrentState.resize(nSeg);
561  li_NaCurrentState.resize(nSeg);
562  segFvalue.resize(nSeg);
563  segQvalue.resize(nSeg);
564  segNEquFvalue.resize(nSeg);
565  segNEquQvalue.resize(nSeg);
566  segMEquFvalue.resize(nSeg);
567  segMEquQvalue.resize(nSeg);
568  segHEquFvalue.resize(nSeg);
569  segHEquQvalue.resize(nSeg);
570  segAEquFvalue.resize(nSeg);
571  segAEquQvalue.resize(nSeg);
572  segBEquFvalue.resize(nSeg);
573  segBEquQvalue.resize(nSeg);
574  segM_EquFvalue.resize(nSeg);
575  segM_EquQvalue.resize(nSeg);
576  segH_EquFvalue.resize(nSeg);
577  segH_EquQvalue.resize(nSeg);
578  segCEquFvalue.resize(nSeg);
579  segCEquQvalue.resize(nSeg);
580  segCaEquFvalue.resize(nSeg);
581  segCaEquQvalue.resize(nSeg);
582 
583  // jacobian elements
584  segF_dVp.resize(nSeg);
585  segF_dV.resize(nSeg);
586  segF_dVn.resize(nSeg);
587  segF_dn.resize(nSeg);
588  segF_dm.resize(nSeg);
589  segF_dh.resize(nSeg);
590  segF_da.resize(nSeg);
591  segF_db.resize(nSeg);
592  segF_dM.resize(nSeg);
593  segF_dH.resize(nSeg);
594  segF_dc.resize(nSeg);
595  segQ_dV.resize(nSeg);
596  dnF_dV.resize(nSeg);
597  dnF_dn.resize(nSeg);
598  dnQ_dn.resize(nSeg);
599  dmF_dV.resize(nSeg);
600  dmF_dm.resize(nSeg);
601  dmQ_dm.resize(nSeg);
602  dhF_dV.resize(nSeg);
603  dhF_dh.resize(nSeg);
604  dhQ_dh.resize(nSeg);
605  daF_dV.resize(nSeg);
606  daF_da.resize(nSeg);
607  daQ_da.resize(nSeg);
608  dbF_dV.resize(nSeg);
609  dbF_db.resize(nSeg);
610  dbQ_db.resize(nSeg);
611  dMF_dV.resize(nSeg);
612  dMF_dM.resize(nSeg);
613  dMQ_dM.resize(nSeg);
614  dHF_dV.resize(nSeg);
615  dHF_dH.resize(nSeg);
616  dHQ_dH.resize(nSeg);
617  dcF_dV.resize(nSeg);
618  dcF_dc.resize(nSeg);
619  dcF_dCa.resize(nSeg);
620  dcQ_dc.resize(nSeg);
621  dCaF_dV.resize(nSeg);
622  dCaF_dM.resize(nSeg);
623  dCaF_dH.resize(nSeg);
624  dCaF_dCa.resize(nSeg);
625  dCaQ_dCa.resize(nSeg);
626 
627  // state vars
628  potassiumCurrent.resize(nSeg);
629  sodiumCurrent.resize(nSeg);
630  }
631  else
632  {
633  /*
634  li_Vol.resize(nSeg);
635  segFvalue.resize(nSeg);
636  segQvalue.resize(nSeg);
637 
638  // jacobian elements
639  segF_dVp.resize(nSeg);
640  segF_dV.resize(nSeg);
641  segF_dVn.resize(nSeg);
642  segQ_dV.resize(nSeg);
643  */
644  }
645 
646 }
647 
648 //-----------------------------------------------------------------------------
649 // Function : Instance::~Instance
650 // Purpose : destructor
651 // Special Notes :
652 // Scope : public
653 // Creator : Richard Schiek, Electrical and Microsytem Modeling
654 // Creation Date : 06/10/09
655 //-----------------------------------------------------------------------------
657 {
658 }
659 
660 //-----------------------------------------------------------------------------
661 // Function : Instance::processParams
662 // Purpose :
663 // Special Notes :
664 // Scope : public
665 // Creator : Richard Schiek, Electrical and Microsytem Modeling
666 // Creation Date : 06/10/09
667 //-----------------------------------------------------------------------------
669 {
670  // If there are any time dependent parameters, set their values at for
671  // the current time.
672 
673  // now set the temperature related stuff.
674  //updateTemperature(temp);
675 
676  return true;
677 }
678 
679 //-----------------------------------------------------------------------------
680 // Function : Instance::updateTemperature
681 // Purpose :
682 // Special Notes :
683 // Scope : public
684 // Creator : Richard Schiek, Electrical and Microsytem Modeling
685 // Creation Date : 06/10/09
686 //-----------------------------------------------------------------------------
687 bool Instance::updateTemperature ( const double & temp)
688 {
689  bool bsuccess = true;
690  return bsuccess;
691 }
692 
693 //-----------------------------------------------------------------------------
694 // Function : Instance::registerLIDs
695 // Purpose :
696 // Special Notes :
697 // Scope : public
698 // Creator : Richard Schiek, Electrical and Microsytem Modeling
699 // Creation Date : 06/10/09
700 //-----------------------------------------------------------------------------
701 void Instance::registerLIDs(const std::vector<int> & intLIDVecRef,
702  const std::vector<int> & extLIDVecRef)
703 {
704  AssertLIDs(intLIDVecRef.size() == numIntVars);
705  AssertLIDs(extLIDVecRef.size() == numExtVars);
706 
707  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
708  {
709  Xyce::dout() << std::endl << section_divider << std::endl;
710  Xyce::dout() << " Instance::registerLIDs" << std::endl;
711  Xyce::dout() << " name = " << getName() << std::endl;
712  }
713 
714  // copy over the global ID lists.
715  intLIDVec = intLIDVecRef;
716  extLIDVec = extLIDVecRef;
717 
718  li_Pos = extLIDVec[0];
719  li_Neg = extLIDVec[1];
720 
721  // resize our storage location for the internal vars.
722  li_internalVars.resize( numIntVars );
723 
724  // now copy in the local ids
725  for( int i=0; i<numIntVars; i++ )
726  {
727  li_internalVars[i] = intLIDVec[i];
728  }
729  /*
730  if( model_.ConnorStevensOn_ )
731  {
732  for( int i=0, j=0; i<nSeg; i++, j+=10)
733  {
734  li_Vol[i] = intLIDVec[j];
735  li_nPro[i] = intLIDVec[j+1];
736  li_mPro[i] = intLIDVec[j+2];
737  li_hPro[i] = intLIDVec[j+3];
738  li_aPro[i] = intLIDVec[j+4];
739  li_bPro[i] = intLIDVec[j+5];
740  li_MPro[i] = intLIDVec[j+6];
741  li_HPro[i] = intLIDVec[j+7];
742  li_cPro[i] = intLIDVec[j+8];
743  li_CaPro[i] = intLIDVec[j+9];
744  }
745  }
746  else
747  {
748  for( int i=0, j=0; i<nSeg; i++, j+=1)
749  {
750  li_Vol[i] = intLIDVec[j];
751  }
752  }
753 
754  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) )
755  {
756  Xyce::dout() << " li_Pos = " << li_Pos << std::endl
757  << " li_Neg = " << li_Neg << std::endl;
758  for( int i=0; i<nSeg; i++ )
759  {
760  Xyce::dout() << " li_Vol[ " << i << " ] = " << li_Vol[i] << std::endl;
761 
762  if( model_.ConnorStevensOn_ )
763  {
764  Xyce::dout() << " li_nPro[ " << i << " ] = " << li_nPro[i] << std::endl
765  << " li_mPro[ " << i << " ] = " << li_mPro[i] << std::endl
766  << " li_hPro[ " << i << " ] = " << li_hPro[i] << std::endl
767  << " li_aPro[ " << i << " ] = " << li_aPro[i] << std::endl
768  << " li_bPro[ " << i << " ] = " << li_bPro[i] << std::endl
769  << " li_MPro[ " << i << " ] = " << li_MPro[i] << std::endl
770  << " li_HPro[ " << i << " ] = " << li_HPro[i] << std::endl
771  << " li_cPro[ " << i << " ] = " << li_cPro[i] << std::endl
772  << " li_CaPro[ " << i << " ] = " << li_CaPro[i] << std::endl;
773  }
774  }
775  }
776  #endif
777 
778  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) )
779  {
780  Xyce::dout() << section_divider << std::endl;
781  }
782  #endif
783  */
784 }
785 
786 //-----------------------------------------------------------------------------
787 // Function : Instance::loadNodeSymbols
788 // Purpose :
789 // Special Notes :
790 // Scope : public
791 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
792 // Creation Date : 05/13/05
793 //-----------------------------------------------------------------------------
794 void Instance::loadNodeSymbols(Util::SymbolTable &symbol_table) const
795 {
796  for (int i = 0; i < nSeg ; i++)
797  {
798  std::ostringstream segNumber;
799  segNumber << i;
800  addInternalNode(symbol_table, li_internalVars[i* numIntVarsPerSegment ], getName(), "V" + segNumber.str());
801  if( numIntVarsPerSegment > 1 )
802  {
803  // need to handle this better as the HH and CS (and userdefined) optinos will have differnet internal variables
804  addInternalNode(symbol_table, li_internalVars[i*numIntVarsPerSegment +1], getName(), "N" + segNumber.str());
805  addInternalNode(symbol_table, li_internalVars[i*numIntVarsPerSegment +2], getName(), "M" + segNumber.str());
806  addInternalNode(symbol_table, li_internalVars[i*numIntVarsPerSegment +3], getName(), "H" + segNumber.str());
807  }
808 
810  {
811  addInternalNode(symbol_table, li_nPro[i], getName(), "N" + segNumber.str());
812  addInternalNode(symbol_table, li_mPro[i], getName(), "M" + segNumber.str());
813  addInternalNode(symbol_table, li_hPro[i], getName(), "H" + segNumber.str());
814  addInternalNode(symbol_table, li_aPro[i], getName(), "A" + segNumber.str());
815  addInternalNode(symbol_table, li_bPro[i], getName(), "B" + segNumber.str());
816  addInternalNode(symbol_table, li_MPro[i], getName(), "M_" + segNumber.str());
817  addInternalNode(symbol_table, li_HPro[i], getName(), "H_" + segNumber.str());
818  addInternalNode(symbol_table, li_cPro[i], getName(), "C" + segNumber.str());
819  addInternalNode(symbol_table, li_CaPro[i], getName(), "Ca" + segNumber.str());
820  }
821  }
822 }
823 
824 //-----------------------------------------------------------------------------
825 // Function : Instance::registerStateLIDs
826 // Purpose :
827 // Special Notes :
828 // Scope : public
829 // Creator : Richard Schiek, Electrical and Microsytem Modeling
830 // Creation Date : 06/10/09
831 //-----------------------------------------------------------------------------
832 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
833 {
834  AssertLIDs(staLIDVecRef.size() == numStateVars);
835 
836  // copy over the global ID lists.
837  staLIDVec = staLIDVecRef;
838 
840  {
841  for( int i=0, j=0; i<nSeg; i++, j+=2)
842  {
843  li_KCurrentState[i] = staLIDVec[j];
844  li_NaCurrentState[i] = staLIDVec[j+1];
845  }
846  }
847  else
848  {
849  }
850 }
851 
852 //-----------------------------------------------------------------------------
853 // Function : Instance::jacobianStamp
854 // Purpose :
855 // Special Notes :
856 // Scope : public
857 // Creator : Richard Schiek, Electrical and Microsytem Modeling
858 // Creation Date : 06/10/09
859 //-----------------------------------------------------------------------------
860 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
861 {
862  return jacStamp;
863 }
864 
865 //-----------------------------------------------------------------------------
866 // Function : Instance::registerJacLIDs
867 // Purpose :
868 // Special Notes :
869 // Scope : public
870 // Creator : Richard Schiek, Electrical and Microsytem Modeling
871 // Creation Date : 06/10/09
872 //-----------------------------------------------------------------------------
873 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
874 {
875  DeviceInstance::registerJacLIDs( jacLIDVec );
876 
877  // resize our storage location and store the results
878 
879  int numRows = jacLIDVec.size();
880  jacobianOffsets.resize( numRows );
881  for( int i=0; i< numRows; i++ )
882  {
883  int numCol = jacLIDVec[i].size();
884  jacobianOffsets[i].resize( numCol );
885  for( int j=0; j< numCol; j++ )
886  {
887  jacobianOffsets[i][j] = jacLIDVec[i][j];
888  }
889  }
890 
891  // external terminals
892  APosEquPosNodeOffset = jacLIDVec[0][0];
893  APosEquNextNodeOffset = jacLIDVec[0][1];
894  ANegEquNegNodeOffset = jacLIDVec[1][0];
895  ANegEquLastNodeOffset = jacLIDVec[1][1];
896  /*
897  Xyce::dout() << "APosEquPosNodeOffset = " << APosEquPosNodeOffset << std::endl;
898  Xyce::dout() << "APosEquNextNodeOffset = " << APosEquNextNodeOffset << std::endl;
899  Xyce::dout() << "ANegEquNegNodeOffset = " << ANegEquNegNodeOffset << std::endl;
900  Xyce::dout() << "ANegEquLastNodeOffset = " << ANegEquLastNodeOffset << std::endl;
901  */
902 
904  {
905  // internal variables
906  SegVEqnVpreOffset.resize(nSeg);
907  SegVEqnVsegOffset.resize(nSeg);
908  SegVEqnVnexOffset.resize(nSeg);
909  SegVEqnNOffset.resize(nSeg);
910  SegVEqnMOffset.resize(nSeg);
911  SegVEqnHOffset.resize(nSeg);
912  NEquVNodeOffset.resize(nSeg);
913  NEquNNodeOffset.resize(nSeg);
914  MEquVNodeOffset.resize(nSeg);
915  MEquMNodeOffset.resize(nSeg);
916  HEquVNodeOffset.resize(nSeg);
917  HEquHNodeOffset.resize(nSeg);
918  AEquVNodeOffset.resize(nSeg);
919  AEquANodeOffset.resize(nSeg);
920  BEquVNodeOffset.resize(nSeg);
921  BEquBNodeOffset.resize(nSeg);
922  M_EquVNodeOffset.resize(nSeg);
923  M_EquM_NodeOffset.resize(nSeg);
924  H_EquVNodeOffset.resize(nSeg);
925  H_EquH_NodeOffset.resize(nSeg);
926  CEquVNodeOffset.resize(nSeg);
927  CEquCNodeOffset.resize(nSeg);
928  CEquCaNodeOffset.resize(nSeg);
929  CaEquVNodeOffset.resize(nSeg);
930  CaEquM_NodeOffset.resize(nSeg);
931  CaEquH_NodeOffset.resize(nSeg);
932  CaEquCaNodeOffset.resize(nSeg);
933 
934  for(int i=0, j=2; i<nSeg; i++, j+=10 )
935  {
936  SegVEqnVpreOffset[i] = jacLIDVec[j][0];
937  SegVEqnVsegOffset[i] = jacLIDVec[j][1];
938  SegVEqnNOffset[i] = jacLIDVec[j][2];
939  SegVEqnMOffset[i] = jacLIDVec[j][3];
940  SegVEqnHOffset[i] = jacLIDVec[j][4];
941  SegVEqnVnexOffset[i] = jacLIDVec[j][5];
942 
943  NEquVNodeOffset[i] = jacLIDVec[j+1][0];
944  NEquNNodeOffset[i] = jacLIDVec[j+1][1];
945  MEquVNodeOffset[i] = jacLIDVec[j+2][0];
946  MEquMNodeOffset[i] = jacLIDVec[j+2][1];
947  HEquVNodeOffset[i] = jacLIDVec[j+3][0];
948  HEquHNodeOffset[i] = jacLIDVec[j+3][1];
949  AEquVNodeOffset[i] = jacLIDVec[j+4][0];
950  AEquANodeOffset[i] = jacLIDVec[j+4][1];
951  BEquVNodeOffset[i] = jacLIDVec[j+5][0];
952  BEquBNodeOffset[i] = jacLIDVec[j+5][1];
953  M_EquVNodeOffset[i] = jacLIDVec[j+6][0];
954  M_EquM_NodeOffset[i] = jacLIDVec[j+6][1];
955  H_EquVNodeOffset[i] = jacLIDVec[j+7][0];
956  H_EquH_NodeOffset[i] = jacLIDVec[j+7][1];
957  CEquVNodeOffset[i] = jacLIDVec[j+8][0];
958  CEquCNodeOffset[i] = jacLIDVec[j+8][1];
959  CEquCaNodeOffset[i] = jacLIDVec[j+8][2];
960  CaEquVNodeOffset[i] = jacLIDVec[j+9][0];
961  CaEquM_NodeOffset[i] = jacLIDVec[j+9][1];
962  CaEquH_NodeOffset[i] = jacLIDVec[j+9][2];
963  CaEquCaNodeOffset[i] = jacLIDVec[j+9][3];
964 
965  /*
966  Xyce::dout() << SegVEqnVpreOffset[i] << ", "
967  << SegVEqnVsegOffset[i] << ", "
968  << SegVEqnNOffset[i] << ", "
969  << SegVEqnMOffset[i] << ", "
970  << SegVEqnHOffset[i] << ", "
971  << SegVEqnVnexOffset[i] << ", "
972  << NEquVNodeOffset[i] << ", "
973  << NEquNNodeOffset[i] << ", "
974  << MEquVNodeOffset[i] << ", "
975  << MEquMNodeOffset[i] << ", "
976  << HEquVNodeOffset[i] << ", "
977  << HEquHNodeOffset[i] << std::endl;
978  */
979  }
980  }
981  else
982  {
983  // internal variables
984  SegVEqnVpreOffset.resize(nSeg);
985  SegVEqnVsegOffset.resize(nSeg);
986  SegVEqnVnexOffset.resize(nSeg);
987 
988  for(int i=0, j=2; i<nSeg; i++, j+=numIntVarsPerSegment )
989  {
990  // Xyce::dout() << " i = " << i << " j = " << j << " jacLIDVec[ " << j << " ].size() = " << jacLIDVec[j].size() << std::endl;
991  SegVEqnVpreOffset[i] = jacLIDVec[j][0];
992  SegVEqnVsegOffset[i] = jacLIDVec[j][1];
993  SegVEqnVnexOffset[i] = jacLIDVec[j][2];
994 
995  /*
996  Xyce::dout() << SegVEqnVpreOffset[i] << ", "
997  << SegVEqnVsegOffset[i] << ", "
998  << SegVEqnVnexOffset[i] << std::endl;
999  */
1000  }
1001  }
1002 
1003 }
1004 
1005 
1006 //-----------------------------------------------------------------------------
1007 // Function : Instance::updateIntermediateVars
1008 // Purpose :
1009 // Special Notes :
1010 // Scope : public
1011 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1012 // Creation Date : 06/10/09
1013 //-----------------------------------------------------------------------------
1015 {
1016  bool bsuccess = true;
1017 
1018  return bsuccess;
1019 }
1020 //-----------------------------------------------------------------------------
1021 // Function : Instance::updatePrimaryState
1022 // Purpose :
1023 // Special Notes :
1024 // Scope : public
1025 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1026 // Creation Date : 06/10/09
1027 //-----------------------------------------------------------------------------
1029 {
1030  bool bsuccess = true;
1031 
1032  return bsuccess;
1033 }
1034 
1035 //-----------------------------------------------------------------------------
1036 // Function : Instance::updateSecondaryState
1037 // Purpose :
1038 // Special Notes :
1039 // Scope : public
1040 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1041 // Creation Date : 06/10/09
1042 //-----------------------------------------------------------------------------
1044 {
1045  bool bsuccess = true;
1046 
1047  return bsuccess;
1048 }
1049 
1050 //-----------------------------------------------------------------------------
1051 // Function : Instance::loadDAEQVector
1052 //
1053 // Purpose : Loads the Q-vector contributions for a single
1054 // Neuron 6 instance.
1055 //
1056 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1057 // which the system of equations is represented as:
1058 //
1059 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1060 //
1061 // Scope : public
1062 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1063 // Creation Date : 06/10/09
1064 //-----------------------------------------------------------------------------
1066 {
1067  bool bsuccess = true;
1068 
1069  Linear::Vector * solVectorPtr = extData.nextSolVectorPtr;
1070  Linear::Vector * daeQVecPtr = extData.daeQVectorPtr;
1071 
1072  // no Q component for the cable component of this devcie
1073 
1074  // now let the membrane model load it's Q component (memCap dV/dt, etc.)
1075  for( int i=0; i<nSeg ; i++)
1076  {
1077  model_.membraneModel_->loadDAEQVector ( i, li_internalVars, solVectorPtr, daeQVecPtr, segArea );
1078  /*
1079  (*daeQVecPtr)[li_Vol[i]] += segQvalue[i];
1080  if( model_.ConnorStevensOn_ )
1081  {
1082  (*daeQVecPtr)[li_nPro[i]] += segNEquQvalue[i];
1083  (*daeQVecPtr)[li_mPro[i]] += segMEquQvalue[i];
1084  (*daeQVecPtr)[li_hPro[i]] += segHEquQvalue[i];
1085  (*daeQVecPtr)[li_aPro[i]] += segAEquQvalue[i];
1086  (*daeQVecPtr)[li_bPro[i]] += segBEquQvalue[i];
1087  (*daeQVecPtr)[li_MPro[i]] += segM_EquQvalue[i];
1088  (*daeQVecPtr)[li_HPro[i]] += segH_EquQvalue[i];
1089  (*daeQVecPtr)[li_cPro[i]] += segCEquQvalue[i];
1090  (*daeQVecPtr)[li_CaPro[i]] += segCaEquQvalue[i];
1091  }
1092  */
1093  }
1094 
1095  return bsuccess;
1096 }
1097 
1098 
1099 
1100 //-----------------------------------------------------------------------------
1101 // Function : Instance::loadDAEFVector
1102 //
1103 // Purpose : Loads the F-vector contributions for a single
1104 // Neuron 6 instance.
1105 //
1106 // Special Notes :
1107 //
1108 // Scope : public
1109 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1110 // Creation Date : 06/10/09
1111 //-----------------------------------------------------------------------------
1113 {
1114  bool bsuccess=true;
1115 
1116  Linear::Vector * solVectorPtr = extData.nextSolVectorPtr;
1117  Linear::Vector * daeFVecPtr = extData.daeFVectorPtr;
1118 
1119  double vIn = (*solVectorPtr)[li_Pos];
1120  double vOut = (*solVectorPtr)[li_Neg];
1121 
1122  // take care of the input and output nodes as they are different
1123  (*daeFVecPtr)[li_Pos] += -2.0 * gSeg * ((*solVectorPtr)[li_internalVars[0]] - vIn );
1124  (*daeFVecPtr)[li_Neg] += -2.0 * gSeg * ((*solVectorPtr)[li_internalVars[(nSeg-1)*numIntVarsPerSegment]] - vOut );
1125 
1126  for( int i=0; i<nSeg ; i++)
1127  {
1128  // for this segment get the values of the local vars
1129  double vSeg = (*solVectorPtr)[li_internalVars[i*numIntVarsPerSegment]];
1130  double vNext = 0.0;
1131  double gNext = 0.0;
1132  if (i == (nSeg - 1))
1133  {
1134  vNext = vOut;
1135  gNext = gSeg * 2.0;
1136  }
1137  else
1138  {
1139  vNext = (*solVectorPtr)[li_internalVars[(i+1)*numIntVarsPerSegment]];
1140  gNext = gSeg;
1141  }
1142  double vPrev = 0.0;
1143  double gPrev = 0.0;
1144  if (i == 0 )
1145  {
1146  vPrev = vIn;
1147  gPrev = gSeg * 2.0;
1148  }
1149  else
1150  {
1151  vPrev = (*solVectorPtr)[li_internalVars[(i-1)*numIntVarsPerSegment]];
1152  gPrev = gSeg;
1153  }
1154 
1155  // li_internalVars lists numIntVarsPerSegment for each segment. V for each segment will
1156  // be first. So, V's offset in li_internalVars is i * numIntVarsPerSegment
1157 
1158  (*daeFVecPtr)[li_internalVars[i*numIntVarsPerSegment]] += - gPrev * (vPrev - vSeg) - gNext * (vNext - vSeg);
1159 
1160  model_.membraneModel_->loadDAEFVector ( i, li_internalVars, solVectorPtr, daeFVecPtr, segArea );
1161 
1162  }
1163 
1164  return bsuccess;
1165 }
1166 
1167 //-----------------------------------------------------------------------------
1168 // Function : Instance::loadDAEdQdx
1169 //
1170 // Purpose : Loads the Q-vector contributions for a single
1171 // Neuron 6 instance.
1172 // Scope : public
1173 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1174 // Creation Date : 06/10/09
1175 //-----------------------------------------------------------------------------
1177 {
1178  bool bsuccess = true;
1179 
1180  Linear::Vector * solVectorPtr = extData.nextSolVectorPtr;
1181  Linear::Matrix * dQdxMatPtr = extData.dQdxMatrixPtr;
1182 
1183  for( int i=0; i<nSeg ; i++)
1184  {
1185  // let the membrane model load it's part
1186  model_.membraneModel_->loadDAEdQdx ( i, segMap[i], li_internalVars, jacobianOffsets, solVectorPtr, dQdxMatPtr, segArea );
1187 
1188  /*
1189  if( model_.ConnorStevensOn_ )
1190  {
1191  (*dQdxMatPtr)[li_nPro[i]][NEquNNodeOffset[i]] += dnQ_dn[i];
1192  (*dQdxMatPtr)[li_mPro[i]][MEquMNodeOffset[i]] += dmQ_dm[i];
1193  (*dQdxMatPtr)[li_hPro[i]][HEquHNodeOffset[i]] += dhQ_dh[i];
1194  (*dQdxMatPtr)[li_aPro[i]][AEquANodeOffset[i]] += daQ_da[i];
1195  (*dQdxMatPtr)[li_bPro[i]][BEquBNodeOffset[i]] += dbQ_db[i];
1196  (*dQdxMatPtr)[li_MPro[i]][M_EquM_NodeOffset[i]] += dMQ_dM[i];
1197  (*dQdxMatPtr)[li_HPro[i]][H_EquH_NodeOffset[i]] += dHQ_dH[i];
1198  (*dQdxMatPtr)[li_cPro[i]][CEquCNodeOffset[i]] += dcQ_dc[i];
1199  (*dQdxMatPtr)[li_CaPro[i]][CaEquCaNodeOffset[i]] += dCaQ_dCa[i];
1200  }
1201  */
1202  }
1203 
1204  return bsuccess;
1205 }
1206 
1207 
1208 
1209 //-----------------------------------------------------------------------------
1210 // Function : Instance::loadDAEdFdx ()
1211 //
1212 // Purpose : Loads the F-vector contributions for a single
1213 // Neuron 6 instance.
1214 //
1215 // Special Notes : This is an algebraic constaint.
1216 //
1217 // Scope : public
1218 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1219 // Creation Date : 06/10/09
1220 //-----------------------------------------------------------------------------
1222 {
1223  bool bsuccess = true;
1224 
1225  Linear::Vector * solVectorPtr = extData.nextSolVectorPtr;
1226  Linear::Matrix * dFdxMatPtr = extData.dFdxMatrixPtr;
1227 
1228  (*dFdxMatPtr)[li_Pos][APosEquPosNodeOffset] += 2.0 * gSeg;
1229  (*dFdxMatPtr)[li_Pos][APosEquNextNodeOffset] += -2.0 * gSeg;
1230 
1231  (*dFdxMatPtr)[li_Neg][ANegEquNegNodeOffset] += 2.0 * gSeg;
1232  (*dFdxMatPtr)[li_Neg][ANegEquLastNodeOffset] += -2.0 * gSeg;
1233 
1234  for( int i=0; i<nSeg ; i++)
1235  {
1236  int offset = i * numIntVarsPerSegment;
1237 
1238  int row = numExtVars + i * numIntVarsPerSegment;
1239 
1240  double gPrev = gSeg;
1241  double gNext = gSeg;
1242  if (i == 0)
1243  {
1244  gPrev = gSeg * 2.0;
1245  }
1246  if (i == (nSeg-1))
1247  {
1248  gNext = gSeg * 2.0;
1249  }
1250 
1251  (*dFdxMatPtr)[li_internalVars[offset]][jacobianOffsets[row][prevMap[i]]] += -gPrev; // Vpre
1252  (*dFdxMatPtr)[li_internalVars[offset]][jacobianOffsets[row][segMap[i]]] += gPrev + gNext; // Vseg
1253  (*dFdxMatPtr)[li_internalVars[offset]][jacobianOffsets[row][nextMap[i]]] += -gNext; // Vnext
1254 
1255  // now let the membrane model load it's part
1256  model_.membraneModel_->loadDAEdFdx ( i, segMap[i], li_internalVars, jacobianOffsets, solVectorPtr, dFdxMatPtr, segArea );
1257 
1258  }
1259 
1260  return bsuccess;
1261 }
1262 
1263 //-----------------------------------------------------------------------------
1264 // Function : Instance::setIC
1265 // Purpose :
1266 // Special Notes :
1267 // Scope : public
1268 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1269 // Creation Date : 06/10/09
1270 //-----------------------------------------------------------------------------
1272 {
1273  bool bsuccess = true;
1274 
1275  return bsuccess;
1276 }
1277 
1278 //-----------------------------------------------------------------------------
1279 // Function : Instance::varTypes
1280 // Purpose :
1281 // Special Notes :
1282 // Scope : public
1283 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1284 // Creation Date : 06/10/09
1285 //-----------------------------------------------------------------------------
1286 void Instance::varTypes( std::vector<char> & varTypeVec )
1287 {
1288  //varTypeVec.resize(1);
1289  //varTypeVec[0] = 'I';
1290 }
1291 
1292 
1293 //-----------------------------------------------------------------------------
1294 // Function : Model::Model
1295 // Purpose : block constructor
1296 // Special Notes :
1297 // Scope : public
1298 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1299 // Creation Date : 06/10/09
1300 //-----------------------------------------------------------------------------
1302  const Configuration & configuration,
1303  const ModelBlock & MB,
1304  const FactoryBlock & factory_block)
1305  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
1306  cMem(0.0),
1307  gMem(0.0),
1308  vRest(0.0),
1309  eNa(0.0),
1310  gNa(0.0),
1311  eK(0.0),
1312  gK(0.0),
1313  eA(0.0),
1314  gA(0.0),
1315  eCa(0.0),
1316  gCa(0.0),
1317  eKCa(0.0),
1318  gKCa(0.0),
1319  CaInit(0.0),
1320  CaGamma(0.0),
1321  CaTau(0.0),
1322  rInt(0.0),
1323  radius(0.0),
1324  length(0.0),
1325  nSeg(0.0),
1326  rIntGiven(false),
1327  radiusGiven(false),
1328  lengthGiven(false),
1329  nSegGiven(false),
1330  ionChannelModelGiven(false),
1331  cMemGiven(false),
1332  gMemGiven(false),
1333  vRestGiven(false),
1334  eNaGiven(false),
1335  gNaGiven(false),
1336  eKGiven(false),
1337  gKGiven(false),
1338  eAGiven(false),
1339  gAGiven(false),
1340  eCaGiven(false),
1341  gCaGiven(false),
1342  eKCaGiven(false),
1343  gKCaGiven(false),
1344  CaInitGiven(false),
1345  CaGammaGiven(false),
1346  CaTauGiven(false),
1347  hodgenHuxleyOn_(false),
1348  ConnorStevensOn_(false),
1349  sodiumOn_(false),
1350  potassiumOn_(false),
1351  aCurrentOn_(false),
1352  calciumOn_(false),
1353  membraneIndpVarsGiven(false),
1354  membraneIndpFEqusGiven(false),
1355  membraneIndpQEqusGiven(false)
1356 {
1357 
1358  // Set params to constant default values:
1359  setDefaultParams ();
1360 
1361  // Set params according to .model line and constant defaults from metadata:
1362  setModParams (MB.params);
1363 
1364  // Set any non-constant parameter defaults:
1365  //if (!given("TNOM"))
1366  // tnom = getDeviceOptions().tnom;
1367 
1368  // Calculate any parameters specified as expressions:
1370 
1371  // calculate dependent (ie computed) params and check for errors:
1372 
1373  processParams ();
1374 
1375  // check the specified model type and allocate the needed membrane model
1376  if( ionChannelModelGiven )
1377  {
1378  // should change the case on ionChannelModel and simplify this set of clauses
1379  if( ionChannelModel == "passive" || ionChannelModel == "PASSIVE" )
1380  {
1382 
1383  }
1384  else if( ionChannelModel == "hh" || ionChannelModel == "HH" )
1385  {
1386  membraneModel_ = rcp( new MembraneHH( getSolverState(), cMem, gMem, vRest, eK, gK, eNa, gNa) );
1387  }
1388  else if( ionChannelModel == "cs" || ionChannelModel == "CS")
1389  {
1390  membraneModel_ = rcp( new MembraneCS( getSolverState() ) );
1391  }
1392  else if( ionChannelModel == "ud" || ionChannelModel == "UD")
1393  {
1396  }
1397  else
1398  {
1399  UserFatal0(*this) << "Model: unknown ion channel model given \"" << ionChannelModel << "\"";
1400  }
1401 
1402  }
1403  else
1404  {
1405  // no model given so assume passive
1407  }
1408 }
1409 
1410 
1411 //-----------------------------------------------------------------------------
1412 // Function : Model::~Model
1413 // Purpose : destructor
1414 // Special Notes :
1415 // Scope : public
1416 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1417 // Creation Date : 06/10/09
1418 //-----------------------------------------------------------------------------
1420 {
1421  std::vector<Instance*>::iterator iter;
1422  std::vector<Instance*>::iterator first = instanceContainer.begin();
1423  std::vector<Instance*>::iterator last = instanceContainer.end();
1424 
1425  for (iter=first; iter!=last; ++iter)
1426  {
1427  delete (*iter);
1428  }
1429 
1430 }
1431 
1432 // additional Declarations
1433 //-----------------------------------------------------------------------------
1434 // Function : Model::processParams
1435 // Purpose :
1436 // Special Notes :
1437 // Scope : public
1438 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1439 // Creation Date : 06/10/09
1440 //-----------------------------------------------------------------------------
1442 {
1443  return true;
1444 }
1445 
1446 //----------------------------------------------------------------------------
1447 // Function : Model::processInstanceParams
1448 // Purpose :
1449 // Special Notes :
1450 // Scope : public
1451 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1452 // Creation Date : 06/10/09
1453 //----------------------------------------------------------------------------
1455 {
1456 
1457  std::vector<Instance*>::iterator iter;
1458  std::vector<Instance*>::iterator first = instanceContainer.begin();
1459  std::vector<Instance*>::iterator last = instanceContainer.end();
1460 
1461  for (iter=first; iter!=last; ++iter)
1462  {
1463  (*iter)->processParams();
1464  }
1465 
1466  return true;
1467 }
1468 //-----------------------------------------------------------------------------
1469 // Function : Model::printOutInstances
1470 // Purpose : debugging tool.
1471 // Special Notes :
1472 // Scope : public
1473 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1474 // Creation Date : 06/10/09
1475 //-----------------------------------------------------------------------------
1476 std::ostream &Model::printOutInstances(std::ostream &os) const
1477 {
1478  std::vector<Instance*>::const_iterator iter;
1479  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1480  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1481 
1482  int i, isize;
1483  isize = instanceContainer.size();
1484 
1485  os << std::endl;
1486  os << "Number of Neuron instances: " << isize << std::endl;
1487  os << " name=\t\tmodelName\tParameters" << std::endl;
1488  for (i=0, iter=first; iter!=last; ++iter, ++i)
1489  {
1490  os << " " << i << ": " << (*iter)->getName() << "\t";
1491  os << getName();
1492  os << std::endl;
1493  }
1494 
1495  os << std::endl;
1496  return os;
1497 }
1498 
1499 //-----------------------------------------------------------------------------
1500 // Function : Model::forEachInstance
1501 // Purpose :
1502 // Special Notes :
1503 // Scope : public
1504 // Creator : David Baur
1505 // Creation Date : 2/4/2014
1506 //-----------------------------------------------------------------------------
1507 /// Apply a device instance "op" to all instances associated with this
1508 /// model
1509 ///
1510 /// @param[in] op Operator to apply to all instances.
1511 ///
1512 ///
1513 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1514 {
1515  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1516  op(*it);
1517 }
1518 
1519 
1520 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1521 {
1522 
1523  return new DeviceMaster<Traits>(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1524 }
1525 
1527 {
1529  .registerDevice("neuron", 6)
1530  .registerModelType("neuron", 6);
1531 }
1532 
1533 } // namespace Neuron6
1534 } // namespace Device
1535 } // namespace Xyce
const InstanceName & getName() const
std::vector< double > segF_dM
std::map< int, int > nextMap
virtual std::ostream & printOutInstances(std::ostream &os) const
std::vector< int > SegVEqnNOffset
std::vector< double > segQ_dV
std::vector< double > dCaF_dH
std::vector< double > segF_dVn
const std::vector< std::vector< int > > & jacobianStamp() const
std::vector< double > segF_dVp
std::vector< double > dHQ_dH
std::vector< double > segCEquFvalue
const SolverState & solverState_
std::vector< double > segMEquQvalue
Descriptor & addPar(const char *parName, T default_value, T U::*varPtr)
Adds the parameter description to the parameter map.
Definition: N_DEV_Pars.h:1429
std::vector< double > dmF_dm
std::vector< double > daQ_da
std::vector< int > li_internalVars
std::vector< int > SegVEqnHOffset
std::vector< double > dbF_dV
std::vector< int > MEquVNodeOffset
std::vector< std::string > membraneIndpFEqus
RCP< MembraneModel > membraneModel_
static void loadModelParameters(ParametricData< Model > &model_parameters)
Linear::Vector * nextSolVectorPtr
std::vector< double > dcF_dCa
std::vector< double > segF_db
std::vector< int > CEquCNodeOffset
std::vector< int > MEquMNodeOffset
bool updateTemperature(const double &temp_tmp)
Linear::Vector * daeQVectorPtr
std::vector< double > daF_dV
Pure virtual class to augment a linear system.
void addInternalNode(Util::SymbolTable &symbol_table, int index, const InstanceName &instance_name, const std::string &lead_name)
bool processParams()
processParams
std::vector< double > segF_dm
std::vector< double > dbQ_db
std::vector< double > dcF_dV
std::vector< std::string > membraneCurrentEqus
std::vector< int > CaEquH_NodeOffset
std::vector< int > M_EquVNodeOffset
#define AssertLIDs(cmp)
std::vector< double > segHEquQvalue
std::map< int, int > segMap
virtual void registerJacLIDs(const JacobianStamp &jacLIDVec)
std::vector< double > dmQ_dm
std::vector< double > segCEquQvalue
std::vector< double > dnF_dn
std::vector< double > dCaF_dV
std::vector< double > segHEquFvalue
static Device * factory(const Configuration &configuration, const FactoryBlock &factory_block)
std::vector< std::string > membraneFunctions
std::vector< int > HEquHNodeOffset
std::vector< double > segF_dc
std::vector< int > H_EquVNodeOffset
std::vector< double > dCaQ_dCa
std::vector< double > segNEquQvalue
std::vector< int > CaEquCaNodeOffset
std::vector< double > segF_dH
std::vector< double > segCaEquQvalue
std::vector< Param > params
Parameters from the line.
void setParams(const std::vector< Param > &params)
const std::string & getName() const
static void loadInstanceParameters(ParametricData< Instance > &instance_parameters)
Definition: N_DEV_Neuron6.C:79
std::vector< int > HEquVNodeOffset
std::vector< int > CaEquM_NodeOffset
std::vector< double > segBEquQvalue
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
std::vector< double > segAEquFvalue
std::vector< double > segM_EquFvalue
std::vector< int > BEquBNodeOffset
void registerJacLIDs(const std::vector< std::vector< int > > &jacLIDVec)
std::vector< double > segMEquFvalue
std::vector< std::string > membraneParameters
std::vector< double > dbF_db
std::vector< double > dnF_dV
std::vector< double > potassiumCurrent
std::vector< double > segCaEquFvalue
std::vector< int > SegVEqnVpreOffset
void registerLIDs(const std::vector< int > &intLIDVecRef, const std::vector< int > &extLIDVecRef)
std::vector< Instance * > instanceContainer
const DeviceOptions & deviceOptions_
void varTypes(std::vector< char > &varTypeVec)
std::vector< double > dhQ_dh
std::map< int, int > prevMap
std::vector< double > segQvalue
std::vector< double > dMF_dV
static Config< T > & addConfiguration()
Adds the device to the Xyce device configuration.
std::vector< double > segF_dh
std::vector< int > AEquVNodeOffset
std::vector< double > segF_dn
Linear::Matrix * dFdxMatrixPtr
std::vector< int > CEquVNodeOffset
std::vector< int > li_NaCurrentState
The Device class is an interface for device implementations.
Definition: N_DEV_Device.h:101
std::vector< std::vector< int > > jacStamp
std::vector< int > SegVEqnVsegOffset
std::vector< double > segM_EquQvalue
std::vector< double > dhF_dh
void loadNodeSymbols(Util::SymbolTable &symbol_table) const
Populates and returns the store name map.
std::vector< int > SegVEqnMOffset
std::vector< double > dhF_dV
Class Configuration contains device configuration data.
void registerStateLIDs(const std::vector< int > &staLIDVecRef)
std::vector< double > dMQ_dM
std::vector< int > H_EquH_NodeOffset
std::vector< std::vector< int > > jacobianOffsets
std::vector< double > segF_da
std::vector< double > segAEquQvalue
std::vector< double > dcQ_dc
std::vector< double > dCaF_dM
std::vector< int > CEquCaNodeOffset
const SolverState & getSolverState() const
std::vector< double > dmF_dV
#define M_PI
std::vector< int > CaEquVNodeOffset
std::vector< double > dHF_dV
std::vector< int > SegVEqnVnexOffset
std::vector< int > NEquVNodeOffset
std::vector< double > dcF_dc
virtual void forEachInstance(DeviceInstanceOp &op) const
Apply a device instance "op" to all instances associated with this model.
std::vector< double > segH_EquQvalue
std::vector< double > segH_EquFvalue
std::vector< int > li_KCurrentState
std::vector< int > BEquVNodeOffset
Linear::Vector * daeFVectorPtr
std::vector< double > dCaF_dCa
std::vector< double > segNEquFvalue
std::vector< double > dMF_dM
std::vector< double > segF_dV
std::vector< int > M_EquM_NodeOffset
std::vector< std::string > membraneIndpVars
std::vector< double > segFvalue
std::vector< double > daF_da
std::vector< std::string > membraneIndpQEqus
Instance(const Configuration &configuration, const InstanceBlock &IB, Model &Miter, const FactoryBlock &factory_block)
bool processInstanceParams()
processInstanceParams
std::vector< double > dnQ_dn
std::vector< int > AEquANodeOffset
ModelBlock represents a .MODEL line from the netlist.
Parameter may be specified as a solution dependent expression from netlist.
Definition: N_DEV_Pars.h:68
std::vector< double > sodiumCurrent
Manages parameter binding for class C.
Definition: N_DEV_Pars.h:214
InstanceBlock represent a device instance line from the netlist.
std::vector< Param > params
std::vector< double > segBEquFvalue
Linear::Matrix * dQdxMatrixPtr
void setModParams(const std::vector< Param > &params)
std::vector< double > dHF_dH
std::vector< int > NEquNNodeOffset