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