Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_Neuron3.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_Neuron3.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.35 $
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 #ifdef HAVE_CMATH
51 #include <cmath>
52 #else
53 #include <math.h>
54 #endif
55 
56 #include <N_UTL_Misc.h>
57 
58 // ---------- Xyce Includes ----------
59 #include <N_DEV_DeviceOptions.h>
60 #include <N_DEV_DeviceMaster.h>
61 #include <N_DEV_ExternData.h>
62 #include <N_DEV_MatrixLoadData.h>
63 #include <N_DEV_Neuron3.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 Neuron3 {
78 
79 
81 {
82 // Set up map for double precision variables:
83  p.addPar ("R", 0.0, false, ParameterType::NO_DEP,
85  &Neuron3::Instance::rIntGiven, U_OHMMM1, CAT_NONE, "Intracellular resistivity");
86 
87  p.addPar ("A", 0.0, false, ParameterType::NO_DEP,
89  &Neuron3::Instance::radiusGiven, U_METER, CAT_NONE, "Segment radius");
90 
91  p.addPar ("L", 0.0, false, ParameterType::NO_DEP,
94 
95  p.addPar ("RPS", 1.0e-6, false, ParameterType::NO_DEP,
97  &Neuron3::Instance::rIntPreviousGiven, U_OHMMM1, CAT_NONE, "Previous segment, intracellular resistivity");
98 
99  p.addPar ("APS", 0.0, false, ParameterType::NO_DEP,
101  &Neuron3::Instance::radiusPreviousGiven, U_METER, CAT_NONE, "Previous segment, segment radius");
102 
103  p.addPar ("LPS", 0.0, false, ParameterType::NO_DEP,
105  &Neuron3::Instance::lengthPreviousGiven, U_METER, CAT_NONE, "Previous segment length");
106 
107  p.addPar ("RNS", 1.0e-6, false, ParameterType::NO_DEP,
109  &Neuron3::Instance::rIntNextGiven, U_OHMMM1, CAT_NONE, "Next segment, intracellular resistivity");
110 
111  p.addPar ("ANS", 0.0, false, ParameterType::NO_DEP,
113  &Neuron3::Instance::radiusNextGiven, U_METER, CAT_NONE, "Next segment, segment radius");
114 
115  p.addPar ("LNS", 0.0, false, ParameterType::NO_DEP,
117  &Neuron3::Instance::lengthNextGiven, U_METER, CAT_NONE, "Next segment length");
118 
119  // add non-double types
121  &Neuron3::Instance::nSegGiven , U_NONE, CAT_NONE, "Number of segments" );
122 }
123 
125 {
126  // Set up map for normal (double) param variables:
127  p.addPar ("CMEM", 0.0, false, ParameterType::NO_DEP,
130  U_FARAD, CAT_NONE, "Membrane capacitance");
131 
132  p.addPar ("GMEM", 0.0, false, ParameterType::NO_DEP,
135  U_OHMM1, CAT_NONE, "Membrane conductance");
136 
137  p.addPar ("VREST", 0.0, false, ParameterType::NO_DEP,
140  U_VOLT, CAT_NONE, "Resting potential");
141 
142  p.addPar ("EK", 0.0, false, ParameterType::NO_DEP,
145  U_VOLT, CAT_NONE, "Potassium resting potential");
146 
147  p.addPar ("GK", 0.0, false, ParameterType::NO_DEP,
150  U_OHMM1, CAT_NONE, "Potassium base conductance");
151 
152  p.addPar ("ENA", 0.0, false, ParameterType::NO_DEP,
155  U_VOLT, CAT_NONE, "Sodium resting potential");
156 
157  p.addPar ("GNA", 0.0, false, ParameterType::NO_DEP,
160  U_OHMM1, CAT_NONE, "Sodium base conductance");
161 
162  p.addPar ("R", 0.0, false, ParameterType::NO_DEP,
165  U_OHMMM1, CAT_NONE, "Intracellular resistivity");
166 
167  p.addPar ("A", 0.0, false, ParameterType::NO_DEP,
170  U_METER, CAT_NONE, "Segment radius");
171 
172  p.addPar ("L", 0.0, false, ParameterType::NO_DEP,
175  U_METER, CAT_NONE, "Cable length");
176 
177  p.addPar ("RPS", 1.0e-6, false, ParameterType::NO_DEP,
180  U_OHMMM1, CAT_NONE, "Previous segment, intracellular resistivity");
181 
182  p.addPar ("APS", 0.0, false, ParameterType::NO_DEP,
185  U_METER, CAT_NONE, "Previous segment, segment radius");
186 
187  p.addPar ("LPS", 0.0, false, ParameterType::NO_DEP,
190  U_METER, CAT_NONE, "Previous segment length");
191 
192  p.addPar ("RNS", 1.0e-6, false, ParameterType::NO_DEP,
195  U_OHMMM1, CAT_NONE, "Next segment, intracellular resistivity");
196 
197  p.addPar ("ANS", 0.0, false, ParameterType::NO_DEP,
200  U_METER, CAT_NONE, "Next segment, segment radius");
201 
202  p.addPar ("LNS", 0.0, false, ParameterType::NO_DEP,
205  U_METER, CAT_NONE, "Next segment length");
206 
207  // add non-double types
209  &Neuron3::Model::nSegGiven , U_NONE, CAT_NONE, "Number of segments" );
210 }
211 
212 
213 
214 //
215 // static class member inits
216 //
217 
218 
219 // Class Instance
220 //-----------------------------------------------------------------------------
221 // Function : Instance::processParams
222 // Purpose :
223 // Special Notes :
224 // Scope : public
225 // Creator : Richard Schiek, Electrical and Microsytem Modeling
226 // Creation Date : 06/10/09
227 //-----------------------------------------------------------------------------
229 {
230  // If there are any time dependent parameters, set their values at for
231  // the current time.
232 
233  // now set the temperature related stuff.
234  //updateTemperature(temp);
235 
236  return true;
237 }
238 
239 //-----------------------------------------------------------------------------
240 // Function : Instance::updateTemperature
241 // Purpose :
242 // Special Notes :
243 // Scope : public
244 // Creator : Richard Schiek, Electrical and Microsytem Modeling
245 // Creation Date : 06/10/09
246 //-----------------------------------------------------------------------------
247 bool Instance::updateTemperature ( const double & temp)
248 {
249  bool bsuccess = true;
250  return bsuccess;
251 }
252 
253 //-----------------------------------------------------------------------------
254 // Function : Instance::Instance
255 // Purpose : constructor
256 // Special Notes :
257 // Scope : public
258 // Creator : Richard Schiek, Electrical and Microsytem Modeling
259 // Creation Date : 06/10/09
260 //-----------------------------------------------------------------------------
262  const Configuration & configuration,
263  const InstanceBlock & IB,
264  Model & Miter,
265  const FactoryBlock & factory_block)
266  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
267  model_(Miter),
268  rInt(0.0),
269  radius(0.0),
270  length(0.0),
271  segArea(0.0),
272  nSeg(0),
273  rIntGiven(false),
274  radiusGiven(false),
275  lengthGiven(false),
276  nSegGiven(false),
277  rIntPrevious(0.0),
278  radiusPrevious(0.0),
279  lengthPrevious(0.0),
280  rIntNext(0.0),
281  radiusNext(0.0),
282  lengthNext(0.0),
283  rIntPreviousGiven(false),
284  radiusPreviousGiven(false),
285  lengthPreviousGiven(false),
286  rIntNextGiven(false),
287  radiusNextGiven(false),
288  lengthNextGiven(false),
289  kcl1Fvalue(0.0),
290  kcl2Fvalue(0.0),
291  dkcl1F_dVin(0.0),
292  dkcl1F_dVs0(0.0),
293  dkcl2F_dVout(0.0),
294  dkcl2F_dVsn(0.0),
295  li_Pos(0),
296  li_Neg(0),
297  APosEquPosNodeOffset(0),
298  APosEquNextNodeOffset(0),
299  ANegEquNegNodeOffset(0),
300  ANegEquLastNodeOffset(0)
301 {
302  // we have pased the model and instance parameters so now we can calculate
303  // the number of internal vars
304  numExtVars = 2; // input and output voltage
305 
306  // Set params to constant default values:
307  setDefaultParams ();
308 
309  // Set params according to instance line
310  setParams (IB.params);
311 
312  // Set any non-constant parameter defaults:
313 
314  //if (!given("TEMP"))
315  // temp = getDeviceOptions().temp.dVal();
316 
317  // Calculate any parameters specified as expressions:
319 
320  // calculate dependent (ie computed) params and check for errors:
321  processParams ();
322 
323  // pull unspecified params out of the model if they weren't specified here
324  if( !nSegGiven && model_.nSegGiven )
325  {
326  nSeg = model_.nSeg;
327  nSegGiven = true;
328  }
329  if( !rIntGiven && model_.rIntGiven )
330  {
331  rInt = model_.rInt;
332  rIntGiven = true;
333  }
334  if( !radiusGiven && model_.radiusGiven )
335  {
336  radius = model_.radius;
337  radiusGiven = true;
338  }
339  if( !lengthGiven && model_.lengthGiven )
340  {
341  length = model_.length;
342  lengthGiven = true;
343  }
344 
345  // if nSeg is still unknown then estimate it via lambda-d rule (TO DO)
346  if( !nSegGiven )
347  {
348  nSeg = 10;
349  }
350 
351  // now that nSeg, length and radius are set calculate segment area
352  segArea = 2.0 * M_PI * radius * length / nSeg;
353 
354  // now we can calculate the number of internal vars
355  numIntVars = nSeg * 4; // ion channel vars + one internal voltage node var for each segment
356  numStateVars = nSeg * 2;
357  int numVars = numExtVars + numIntVars;
358 
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
362  //
363  // Vin : g(0,1) * (V(1) - Vin ) = 0
364  // Vout : g(n,n-1) * (V(n-1) - Vout) = 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
369  // Vin Vout V1 n m h V2 n m h V(nSeg) n m h
370  // kcl Vin -g(0,1) g(0,1)
371  // kcl Vout -g(n,n-1) g(n,n-1)
372  // kcl V1 yes yes yes yes yes yes
373  // a yes yes
374  // b yes yes
375  // m yes yes
376  // kcl V2 yes yes yes yes yes yes
377  // a 2 yes yes
378  // b 2 yes yes
379  // m 2 yes yes
380  // kcl VnSeg yes yes yes yes yes yes
381  // a nSeg yes yes
382  // b nSeg yes yes
383  // m nSeg yes yes
384  //
385  // jacobian element count by row:
386  // vin: 2
387  // vout: 2
388  // v1: 6
389  // a1: 2
390  // b1: 2
391  // m1: 2
392  // v2: 6
393  // a2: 2
394  // b2: 2
395  // m2: 2
396  // vnSeg:6
397  // a: 2
398  // b: 2
399  // m: 2
400  //
401  // set up jacStamp
402  if( jacStamp.empty() ) // redundant as jacStamp is not static for this device
403  { // it can't be as each cable may have a different number of nodes
404  jacStamp.resize(numVars);
405  jacStamp[0].resize(2);
406  jacStamp[0][0] = 0;
407  jacStamp[0][1] = 1;
408  jacStamp[1].resize(2);
409  jacStamp[1][0] = 1;
410  jacStamp[1][1] = numVars - 4;
411  for( int i=2; i<numVars; i+=4)
412  {
413  jacStamp[i].resize(6);
414  if( i == 2 )
415  {
416  jacStamp[i][0] = 0;
417  }
418  else
419  {
420  jacStamp[i][0] = i-4;
421  }
422  jacStamp[i][1] = i;
423  jacStamp[i][2] = i+1;
424  jacStamp[i][3] = i+2;
425  jacStamp[i][4] = i+3;
426  if( i==(numVars-4) )
427  {
428  jacStamp[i][5] = 1;
429  }
430  else
431  {
432  jacStamp[i][5] = i+4;
433  }
434  jacStamp[i+1].resize(2);
435  jacStamp[i+1][0] = i;
436  jacStamp[i+1][1] = i+1;
437  jacStamp[i+2].resize(2);
438  jacStamp[i+2][0] = i;
439  jacStamp[i+2][1] = i+2;
440  jacStamp[i+3].resize(2);
441  jacStamp[i+3][0] = i;
442  jacStamp[i+3][1] = i+3;
443  }
444 
445  }
446 
447  /*
448  // print out jacStamp
449  int numRows = jacStamp.size();
450  for( int i=0; i< numRows; i++ )
451  {
452  int numCol = jacStamp[i].size();
453  Xyce::dout() << "jacStamp[ " << i << " ] = { ";
454  for(int j=0; j<numCol; j++)
455  {
456  Xyce::dout() << jacStamp[i][j] << " ";
457  }
458  Xyce::dout() << " } " << std::endl;
459  }
460  Xyce::dout() << std::endl;
461  */
462 
463  // calculate segment conductivities used in load calls:
464  // Note: conductivity to the previous and next segment is not symmetric if the segment length and/or radius is not are not equal
465  // the full formula is:
466  // g(n,n') = radius * (radius')^2 / ( rInt segLength * ( segLength * (radius')^2 + segLength' * (radius)^2 ) )
467  //
468  // equation 6.30 Theoretical neuroscience: computational and mathematical modeling of neural systems, Peter Dayan and L. F. Abbot 2001
469  // If we allow variable segment lengths and radii then we'll need to update this calculation
470  //
471  // Note: the above equation has the wrong units unless rInt (which is Ohm Length) is rLong (which is Ohm/Length).
472  //
473  gForward.resize(nSeg);
474  gBackward.resize(nSeg);
475  double segLength = length / nSeg;
476  double rLong = rInt / (M_PI * radius * radius); // longitudinal resistivity (ohm/length)
477  gBackward[0] = radius * (radiusPrevious * radiusPrevious) / (rLong * segLength * ( segLength * radiusPrevious * radiusPrevious + lengthPrevious * radius * radius ));
478  gForward[0] = radius * (radius * radius) / (rLong * segLength * ( segLength * radius * radius + segLength * radius * radius ));
479  gBackward[nSeg-1] = radius * (radius * radius) / (rLong * segLength * ( segLength * radius * radius + segLength * radius * radius ));
480  gForward[nSeg-1] = radius * (radiusNext * radiusNext) / (rLong * segLength * ( segLength * radiusNext * radiusNext + lengthNext * radius * radius ));
481  for(int i=1; i<(nSeg-1); i++)
482  {
483  gBackward[i] = radius * (radius * radius) / (rLong * segLength * ( segLength * radius * radius + segLength * radius * radius ));
484  gForward[i] = gBackward[i];
485  }
486  /*
487  gBackward[0] = radius * (radiusPrevious * radiusPrevious) / (rInt * segLength * ( segLength * radiusPrevious * radiusPrevious + lengthPrevious * radius * radius ));
488  gForward[0] = radius * (radius * radius) / (rInt * segLength * ( segLength * radius * radius + segLength * radius * radius ));
489  gBackward[nSeg-1] = radius * (radius * radius) / (rInt * segLength * ( segLength * radius * radius + segLength * radius * radius ));
490  gForward[nSeg-1] = radius * (radiusNext * radiusNext) / (rInt * segLength * ( segLength * radiusNext * radiusNext + lengthNext * radius * radius ));
491  for(int i=1; i<(nSeg-1); i++)
492  {
493  gBackward[i] = radius * (radius * radius) / (rInt * segLength * ( segLength * radius * radius + segLength * radius * radius ));
494  gForward[i] = gBackward[i];
495  }
496  */
497  // allocate space for load and jacobian terms per segment
498  // variable indecies loads
499  li_Vol.resize(nSeg);
500  li_nPro.resize(nSeg);
501  li_mPro.resize(nSeg);
502  li_hPro.resize(nSeg);
503  li_KCurrentState.resize(nSeg);
504  li_NaCurrentState.resize(nSeg);
505  segFvalue.resize(nSeg);
506  segQvalue.resize(nSeg);
507  segNEquFvalue.resize(nSeg);
508  segNEquQvalue.resize(nSeg);
509  segMEquFvalue.resize(nSeg);
510  segMEquQvalue.resize(nSeg);
511  segHEquFvalue.resize(nSeg);
512  segHEquQvalue.resize(nSeg);
513 
514  // jacobian elements
515  segF_dVp.resize(nSeg);
516  segF_dV.resize(nSeg);
517  segF_dVn.resize(nSeg);
518  segF_dn.resize(nSeg);
519  segF_dm.resize(nSeg);
520  segF_dh.resize(nSeg);
521  segQ_dV.resize(nSeg);
522  dnF_dV.resize(nSeg);
523  dnF_dn.resize(nSeg);
524  dnQ_dn.resize(nSeg);
525  dmF_dV.resize(nSeg);
526  dmF_dm.resize(nSeg);
527  dmQ_dm.resize(nSeg);
528  dhF_dV.resize(nSeg);
529  dhF_dh.resize(nSeg);
530  dhQ_dh.resize(nSeg);
531 
532  // state vars
533  potassiumCurrent.resize(nSeg);
534  sodiumCurrent.resize(nSeg);
535 
536 }
537 
538 //-----------------------------------------------------------------------------
539 // Function : Instance::~Instance
540 // Purpose : destructor
541 // Special Notes :
542 // Scope : public
543 // Creator : Richard Schiek, Electrical and Microsytem Modeling
544 // Creation Date : 06/10/09
545 //-----------------------------------------------------------------------------
547 {
548 }
549 
550 //-----------------------------------------------------------------------------
551 // Function : Instance::registerLIDs
552 // Purpose :
553 // Special Notes :
554 // Scope : public
555 // Creator : Richard Schiek, Electrical and Microsytem Modeling
556 // Creation Date : 06/10/09
557 //-----------------------------------------------------------------------------
558 void Instance::registerLIDs(const std::vector<int> & intLIDVecRef,
559  const std::vector<int> & extLIDVecRef)
560 {
561  AssertLIDs(intLIDVecRef.size() == numIntVars);
562  AssertLIDs(extLIDVecRef.size() == numExtVars);
563 
564 #ifdef Xyce_DEBUG_DEVICE
565  if (getDeviceOptions().debugLevel > 0)
566  {
567  Xyce::dout() << std::endl << section_divider << std::endl;
568  Xyce::dout() << " Instance::registerLIDs" << std::endl;
569  Xyce::dout() << " name = " << getName() << std::endl;
570  }
571 #endif
572 
573  // copy over the global ID lists.
574  intLIDVec = intLIDVecRef;
575  extLIDVec = extLIDVecRef;
576 
577  li_Pos = extLIDVec[0];
578  li_Neg = extLIDVec[1];
579  for( int i=0, j=0; i<nSeg; i++, j+=4)
580  {
581  li_Vol[i] = intLIDVec[j];
582  li_nPro[i] = intLIDVec[j+1];
583  li_mPro[i] = intLIDVec[j+2];
584  li_hPro[i] = intLIDVec[j+3];
585  }
586 
587 #ifdef Xyce_DEBUG_DEVICE
588  if (getDeviceOptions().debugLevel > 0 )
589  {
590  Xyce::dout() << " li_Pos = " << li_Pos << std::endl
591  << " li_Neg = " << li_Neg << std::endl;
592  for( int i=0; i<nSeg; i++ )
593  {
594  Xyce::dout() << " li_Vol[ " << i << " ] = " << li_Vol[i] << std::endl
595  << " li_nPro[ " << i << " ] = " << li_nPro[i] << std::endl
596  << " li_mPro[ " << i << " ] = " << li_mPro[i] << std::endl
597  << " li_hPro[ " << i << " ] = " << li_hPro[i] << std::endl;
598  }
599  }
600 #endif
601 
602 #ifdef Xyce_DEBUG_DEVICE
603  if (getDeviceOptions().debugLevel > 0 )
604  {
605  Xyce::dout() << section_divider << std::endl;
606  }
607 #endif
608 }
609 
610 //-----------------------------------------------------------------------------
611 // Function : Instance::getIntNameMap
612 // Purpose :
613 // Special Notes :
614 // Scope : public
615 // Creator : Richard Schiek, Electrical and Microsytem Modeling
616 // Creation Date : 06/10/09
617 //-----------------------------------------------------------------------------
618 std::map<int,std::string> & Instance::getIntNameMap ()
619 {
620  // set up the internal name map, if it hasn't been already.
621  if (intNameMap.empty ())
622  {
623  std::string tmpstr;
624  for( int i=0; i<nSeg; i++)
625  {
626  std::ostringstream segNumber;
627  segNumber << i;
628  intNameMap[ li_Vol[i] ] = spiceInternalName(getName(), "V" + segNumber.str());
629  intNameMap[ li_nPro[i] ] = spiceInternalName(getName(), "N" + segNumber.str());
630  intNameMap[ li_mPro[i] ] = spiceInternalName(getName(), "M" + segNumber.str());
631  intNameMap[ li_hPro[i] ] = spiceInternalName(getName(), "H" + segNumber.str());
632  }
633  }
634  return intNameMap;
635 }
636 
637 //-----------------------------------------------------------------------------
638 // Function : Instance::registerStateLIDs
639 // Purpose :
640 // Special Notes :
641 // Scope : public
642 // Creator : Richard Schiek, Electrical and Microsytem Modeling
643 // Creation Date : 06/10/09
644 //-----------------------------------------------------------------------------
645 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
646 {
647  AssertLIDs(staLIDVecRef.size() == numStateVars);
648 
649  // copy over the global ID lists.
650  staLIDVec = staLIDVecRef;
651 
652  for( int i=0, j=0; i<nSeg; i++, j+=2)
653  {
654  li_KCurrentState[i] = staLIDVec[j];
655  li_NaCurrentState[i] = staLIDVec[j+1];
656  }
657 
658 }
659 
660 //-----------------------------------------------------------------------------
661 // Function : Instance::loadDeviceMask
662 //
663 // Purpose : Loads the zero elements of the device mask
664 //
665 // Special Notes : elements of the error vector associated with zero
666 // elements of the mask will not be included in weighted
667 // norms by the time integrator.
668 //
669 // Scope : public
670 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
671 // Creation Date : 06/10/09
672 //-----------------------------------------------------------------------------
674 {
675  bool returnVal=false;
676  N_LAS_Vector * maskVectorPtr = extData.deviceMaskVectorPtr;
677 
678 // Xyce::dout() << "Masking n, m and h" << std::endl;
679 // (*maskVectorPtr)[li_nPro] = 0.0;
680 // (*maskVectorPtr)[li_mPro] = 0.0;
681 // (*maskVectorPtr)[li_hPro] = 0.0;
682 // returnVal = true;
683 
684  return (returnVal);
685 }
686 
687 //-----------------------------------------------------------------------------
688 // Function : Instance::jacobianStamp
689 // Purpose :
690 // Special Notes :
691 // Scope : public
692 // Creator : Richard Schiek, Electrical and Microsytem Modeling
693 // Creation Date : 06/10/09
694 //-----------------------------------------------------------------------------
695 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
696 {
697  return jacStamp;
698 }
699 
700 //-----------------------------------------------------------------------------
701 // Function : Instance::registerJacLIDs
702 // Purpose :
703 // Special Notes :
704 // Scope : public
705 // Creator : Richard Schiek, Electrical and Microsytem Modeling
706 // Creation Date : 06/10/09
707 //-----------------------------------------------------------------------------
708 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
709 {
710  DeviceInstance::registerJacLIDs( jacLIDVec );
711 
712  // external terminals
713  APosEquPosNodeOffset = jacLIDVec[0][0];
714  APosEquNextNodeOffset = jacLIDVec[0][1];
715  ANegEquNegNodeOffset = jacLIDVec[1][0];
716  ANegEquLastNodeOffset = jacLIDVec[1][1];
717  /*
718  Xyce::dout() << "APosEquPosNodeOffset = " << APosEquPosNodeOffset << std::endl;
719  Xyce::dout() << "APosEquNextNodeOffset = " << APosEquNextNodeOffset << std::endl;
720  Xyce::dout() << "ANegEquNegNodeOffset = " << ANegEquNegNodeOffset << std::endl;
721  Xyce::dout() << "ANegEquLastNodeOffset = " << ANegEquLastNodeOffset << std::endl;
722  */
723 
724  // internal variables
725  SegVEqnVpreOffset.resize(nSeg);
726  SegVEqnVsegOffset.resize(nSeg);
727  SegVEqnVnexOffset.resize(nSeg);
728  SegVEqnNOffset.resize(nSeg);
729  SegVEqnMOffset.resize(nSeg);
730  SegVEqnHOffset.resize(nSeg);
731  NEquVNodeOffset.resize(nSeg);
732  NEquNNodeOffset.resize(nSeg);
733  MEquVNodeOffset.resize(nSeg);
734  MEquMNodeOffset.resize(nSeg);
735  HEquVNodeOffset.resize(nSeg);
736  HEquHNodeOffset.resize(nSeg);
737  for(int i=0, j=2; i<nSeg; i++, j+=4 )
738  {
739  SegVEqnVpreOffset[i] = jacLIDVec[j][0];
740  SegVEqnVsegOffset[i] = jacLIDVec[j][1];
741  SegVEqnNOffset[i] = jacLIDVec[j][2];
742  SegVEqnMOffset[i] = jacLIDVec[j][3];
743  SegVEqnHOffset[i] = jacLIDVec[j][4];
744  SegVEqnVnexOffset[i] = jacLIDVec[j][5];
745 
746  NEquVNodeOffset[i] = jacLIDVec[j+1][0];
747  NEquNNodeOffset[i] = jacLIDVec[j+1][1];
748  MEquVNodeOffset[i] = jacLIDVec[j+2][0];
749  MEquMNodeOffset[i] = jacLIDVec[j+2][1];
750  HEquVNodeOffset[i] = jacLIDVec[j+3][0];
751  HEquHNodeOffset[i] = jacLIDVec[j+3][1];
752  /*
753  Xyce::dout() << SegVEqnVpreOffset[i] << ", "
754  << SegVEqnVsegOffset[i] << ", "
755  << SegVEqnNOffset[i] << ", "
756  << SegVEqnMOffset[i] << ", "
757  << SegVEqnHOffset[i] << ", "
758  << SegVEqnVnexOffset[i] << ", "
759  << NEquVNodeOffset[i] << ", "
760  << NEquNNodeOffset[i] << ", "
761  << MEquVNodeOffset[i] << ", "
762  << MEquMNodeOffset[i] << ", "
763  << HEquVNodeOffset[i] << ", "
764  << HEquHNodeOffset[i] << std::endl;
765  */
766  }
767 }
768 
769 
770 //-----------------------------------------------------------------------------
771 // Function : Instance::updateIntermediateVars
772 // Purpose :
773 // Special Notes :
774 // Scope : public
775 // Creator : Richard Schiek, Electrical and Microsytem Modeling
776 // Creation Date : 06/10/09
777 //-----------------------------------------------------------------------------
779 {
780  //Xyce::dout() << "Instance::updateIntermediateVars()" << std::endl;
781 
782  bool bsuccess = true;
783 
784  // here we take the current solutions for V1, V2, n, m and h
785  // and use those to calculate all the terms needed for the next
786  // load cycle (F, Q, dFdX, dQdX)
787  N_LAS_Vector * solVectorPtr = extData.nextSolVectorPtr;
788 
789  double vIn = (*solVectorPtr)[li_Pos];
790  double vOut = (*solVectorPtr)[li_Neg];
791 
792  // take care of the input and output nodes as they are different
793  kcl1Fvalue = gForward[0] * ((*solVectorPtr)[li_Vol[0]] - vIn );
794  dkcl1F_dVin = -gForward[0];
795  dkcl1F_dVs0 = gForward[0];
796  kcl2Fvalue = gBackward[nSeg-1] * ((*solVectorPtr)[li_Vol[nSeg-1]] - vOut );
799  //Xyce::dout() << "end update: " << vIn << ", " << vOut << ", " << gForward[0] << ", " << gBackward[nSeg-1] << std::endl;
800 
801  // loop over segments getting all the load and jacobian terms for each segment
802  for( int i=0; i<nSeg; i++ )
803  {
804  // for this segment get the values of the local vars
805  double vSeg = (*solVectorPtr)[li_Vol[i]];
806  double vNext = 0.0;
807  if (i == (nSeg - 1))
808  {
809  vNext = vOut;
810  }
811  else
812  {
813  vNext = (*solVectorPtr)[li_Vol[i+1]];
814  }
815  double vPrev = 0.0;
816  if (i == 0 )
817  {
818  vPrev = vIn;
819  }
820  else
821  {
822  vPrev = (*solVectorPtr)[li_Vol[i-1]];
823  }
824  double nVarSeg = (*solVectorPtr)[li_nPro[i]];
825  double mVarSeg = (*solVectorPtr)[li_mPro[i]];
826  double hVarSeg = (*solVectorPtr)[li_hPro[i]];
827 
828  // do the voltage equation for this node
829  // get function and derivative values as we go.
830  {
831  // F part
832  // use scoping to avoid lots of similar variable names
833  const int numDeriv = 6;
834  Sacado::Fad::SFad<double,6> vVar( numDeriv, 0, vSeg );
835  Sacado::Fad::SFad<double,6> vVpr( numDeriv, 1, vPrev );
836  Sacado::Fad::SFad<double,6> vVne( numDeriv, 2, vNext );
837  Sacado::Fad::SFad<double,6> nVar( numDeriv, 3, nVarSeg );
838  Sacado::Fad::SFad<double,6> mVar( numDeriv, 4, mVarSeg );
839  Sacado::Fad::SFad<double,6> hVar( numDeriv, 5, hVarSeg );
840  // parameters
841  Sacado::Fad::SFad<double,6> gPrev( gBackward[i] );
842  Sacado::Fad::SFad<double,6> gNext( gForward[i] );
843  Sacado::Fad::SFad<double,6> gMemVar( model_.gMem * segArea );
844  Sacado::Fad::SFad<double,6> vRestVar( model_.vRest );
845  Sacado::Fad::SFad<double,6> gKVar( model_.gK * segArea );
846  Sacado::Fad::SFad<double,6> eKVar( model_.eK );
847  Sacado::Fad::SFad<double,6> gNaVar( model_.gNa * segArea );
848  Sacado::Fad::SFad<double,6> eNaVar( model_.eNa );
849  //Xyce::dout() << "segment update: " << i << ", " << vSeg << ", " << vPrev << ", " << vNext << ", " << gBackward[i] << ", " << gForward[i] << std::endl;
850  // compute the value and derivative terms for KCL 1 F
851  Sacado::Fad::SFad<double,6> resultFad;
852  resultFad = kcl1EquF( vVar, vVpr, vVne, nVar, mVar, hVar, gPrev, gNext, gMemVar, vRestVar, gKVar, eKVar, gNaVar, eNaVar );
853  segFvalue[i] = resultFad.val();
854  segF_dV[i] = resultFad.dx(0);
855  segF_dVp[i] = resultFad.dx(1);
856  segF_dVn[i] = resultFad.dx(2);
857  segF_dn[i] = resultFad.dx(3);
858  segF_dm[i] = resultFad.dx(4);
859  segF_dh[i] = resultFad.dx(5);
860  }
861  {
862  // Q part
863  const int numDeriv = 2;
864  Sacado::Fad::SFad<double,2> vVar( numDeriv, 0, vSeg );
865 
866  // parameters
867  Sacado::Fad::SFad<double,2> cMemVar( model_.cMem * segArea );
868 
869  Sacado::Fad::SFad<double,2> resultFad;
870  resultFad = kcl1EquQ( vVar, cMemVar );
871  segQvalue[i] = resultFad.val();
872  segQ_dV[i] = resultFad.dx(0);
873 
874  }
875 
876  // n - equation
877  {
878  const int numDeriv = 2;
879  Sacado::Fad::SFad<double,2> vVar( numDeriv, 0, vSeg );
880  Sacado::Fad::SFad<double,2> nVar( numDeriv, 1, nVarSeg );
881  // parameter
882  Sacado::Fad::SFad<double,2> vRestVar( model_.vRest );
883 
884  Sacado::Fad::SFad<double,2> resultFad = nEquF( vVar, nVar, vRestVar);
885  segNEquFvalue[i] = resultFad.val();
886  dnF_dV[i] = resultFad.dx(0);
887  dnF_dn[i] = resultFad.dx(1);
888  }
889  {
890  const int numDeriv = 1;
891  Sacado::Fad::SFad<double,1> nVar( numDeriv, 0, nVarSeg );
892 
893  Sacado::Fad::SFad<double,1> resultFad = nEquQ( nVar );
894  segNEquQvalue[i] = resultFad.val();
895  dnQ_dn[i] = resultFad.dx(0);
896  }
897 
898  // m - equation
899  {
900  const int numDeriv = 2;
901  Sacado::Fad::SFad<double,2> vVar( numDeriv, 0, vSeg );
902  Sacado::Fad::SFad<double,2> mVar( numDeriv, 1, mVarSeg );
903  // parameter
904  Sacado::Fad::SFad<double,2> vRestVar( model_.vRest );
905 
906  Sacado::Fad::SFad<double,2> resultFad = mEquF( vVar, mVar, vRestVar );
907  segMEquFvalue[i] = resultFad.val();
908  dmF_dV[i] = resultFad.dx(0);
909  dmF_dm[i] = resultFad.dx(1);
910  }
911  {
912  const int numDeriv = 1;
913  Sacado::Fad::SFad<double,1> mVar( numDeriv, 0, mVarSeg );
914 
915  Sacado::Fad::SFad<double,1> resultFad = mEquQ( mVar );
916  segMEquQvalue[i] = resultFad.val();
917  dmQ_dm[i] = resultFad.dx(0);
918  }
919 
920  // h - equation
921  {
922  const int numDeriv = 2;
923  Sacado::Fad::SFad<double,2> vVar( numDeriv, 0, vSeg );
924  Sacado::Fad::SFad<double,2> hVar( numDeriv, 1, hVarSeg );
925  // parameter
926  Sacado::Fad::SFad<double,2> vRestVar( model_.vRest );
927 
928  Sacado::Fad::SFad<double,2> resultFad = hEquF( vVar, hVar, vRestVar );
929  segHEquFvalue[i] = resultFad.val();
930  dhF_dV[i] = resultFad.dx(0);
931  dhF_dh[i] = resultFad.dx(1);
932  }
933  {
934  const int numDeriv = 1;
935  Sacado::Fad::SFad<double,1> hVar( numDeriv, 0, hVarSeg );
936 
937  Sacado::Fad::SFad<double,1> resultFad = hEquQ( hVar );
938  segHEquQvalue[i] = resultFad.val();
939  dhQ_dh[i] = resultFad.dx(0);
940  }
941 
942  // calculate potassium current
943  potassiumCurrent[i] = model_.gK * pow(nVarSeg, 4.0) * (vSeg - model_.eK);
944 
945  // calculate sodium current
946  sodiumCurrent[i] = model_.gNa * pow(mVarSeg, 3.0) * hVarSeg * (vSeg - model_.eNa);
947 
948 #ifdef Xyce_DEBUG_DEVICE
950  {
951  Xyce::dout() << "Segment " << i << std::endl
952  << "vPrev = " << vPrev << std::endl
953  << "vSeg = " << vSeg << std::endl
954  << "vNext = " << vNext << std::endl
955  << "n, m, h = " << nVarSeg << ", " << mVarSeg << ", " << hVarSeg << std::endl
956  << "segFvalue = " << segFvalue[i] << std::endl
957  << "segQvalue = " << segQvalue[i] << std::endl
958  << "segNEquFvalue = " << segNEquFvalue[i] << std::endl
959  << "segNEquQvalue = " << segNEquQvalue[i] << std::endl
960  << "segMEquFvalue = " << segMEquFvalue[i] << std::endl
961  << "segMEquQvalue = " << segMEquQvalue[i] << std::endl
962  << "segHEquFvalue = " << segHEquFvalue[i] << std::endl
963  << "segHEquQvalue = " << segHEquQvalue[i] << std::endl
964  << std::endl;
965 
966  }
967 #endif
968 
969 
970  }
971 
972 
973 
974  return bsuccess;
975 }
976 //-----------------------------------------------------------------------------
977 // Function : Instance::updatePrimaryState
978 // Purpose :
979 // Special Notes :
980 // Scope : public
981 // Creator : Richard Schiek, Electrical and Microsytem Modeling
982 // Creation Date : 06/10/09
983 //-----------------------------------------------------------------------------
985 {
986  bool bsuccess = true;
987 
989 
990  N_LAS_Vector * solVectorPtr = extData.nextSolVectorPtr;
991  N_LAS_Vector * staVectorPtr = extData.nextStaVectorPtr;
992 
993  for( int i=0; i<nSeg; i++)
994  {
995  (*staVectorPtr)[li_KCurrentState[i]] = potassiumCurrent[i];
996  (*staVectorPtr)[li_NaCurrentState[i]] = sodiumCurrent[i];
997  }
998 
999  return bsuccess;
1000 }
1001 
1002 //-----------------------------------------------------------------------------
1003 // Function : Instance::updateSecondaryState
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  N_LAS_Vector * staVectorPtr = extData.nextStaVectorPtr;
1014 
1015  return bsuccess;
1016 }
1017 
1018 //-----------------------------------------------------------------------------
1019 // Function : Instance::loadDAEQVector
1020 //
1021 // Purpose : Loads the Q-vector contributions
1022 //
1023 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1024 // which the system of equations is represented as:
1025 //
1026 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1027 //
1028 // Scope : public
1029 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1030 // Creation Date : 06/10/09
1031 //-----------------------------------------------------------------------------
1033 {
1034  bool bsuccess = true;
1035 
1036  N_LAS_Vector * daeQVecPtr = extData.daeQVectorPtr;
1037 
1038  for( int i=0; i<nSeg ; i++)
1039  {
1040  (*daeQVecPtr)[li_Vol[i]] += segQvalue[i];
1041  (*daeQVecPtr)[li_nPro[i]] += segNEquQvalue[i];
1042  (*daeQVecPtr)[li_mPro[i]] += segMEquQvalue[i];
1043  (*daeQVecPtr)[li_hPro[i]] += segHEquQvalue[i];
1044  }
1045 
1046  return bsuccess;
1047 }
1048 
1049 
1050 
1051 //-----------------------------------------------------------------------------
1052 // Function : Instance::loadDAEFVector
1053 //
1054 // Purpose : Loads the F-vector contributions for a single
1055 // Neuron 3 instance.
1056 //
1057 // Special Notes :
1058 //
1059 // Scope : public
1060 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1061 // Creation Date : 06/10/09
1062 //-----------------------------------------------------------------------------
1064 {
1065  bool bsuccess=true;
1066 
1067  N_LAS_Vector * daeFVecPtr = extData.daeFVectorPtr;
1068 
1069  (*daeFVecPtr)[li_Pos] += kcl1Fvalue;
1070  (*daeFVecPtr)[li_Neg] += kcl2Fvalue;
1071 
1072  for( int i=0; i<nSeg ; i++)
1073  {
1074  (*daeFVecPtr)[li_Vol[i]] += segFvalue[i];
1075  (*daeFVecPtr)[li_nPro[i]] += segNEquFvalue[i];
1076  (*daeFVecPtr)[li_mPro[i]] += segMEquFvalue[i];
1077  (*daeFVecPtr)[li_hPro[i]] += segHEquFvalue[i];
1078  }
1079 
1080  return bsuccess;
1081 }
1082 
1083 //-----------------------------------------------------------------------------
1084 // Function : Instance::loadDAEdQdx
1085 //
1086 // Purpose : Loads the Q-vector contributions for a single
1087 // Neuron 3 instance.
1088 // Scope : public
1089 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1090 // Creation Date : 06/10/09
1091 //-----------------------------------------------------------------------------
1093 {
1094  bool bsuccess = true;
1095 
1096  N_LAS_Matrix * dQdxMatPtr = extData.dQdxMatrixPtr;
1097 
1098  for( int i=0; i<nSeg ; i++)
1099  {
1100  (*dQdxMatPtr)[li_Vol[i]][SegVEqnVsegOffset[i]] += segQ_dV[i];
1101  (*dQdxMatPtr)[li_nPro[i]][NEquNNodeOffset[i]] += dnQ_dn[i];
1102  (*dQdxMatPtr)[li_mPro[i]][MEquMNodeOffset[i]] += dmQ_dm[i];
1103  (*dQdxMatPtr)[li_hPro[i]][HEquHNodeOffset[i]] += dhQ_dh[i];
1104  }
1105 
1106  return bsuccess;
1107 }
1108 
1109 //-----------------------------------------------------------------------------
1110 // Function : Instance::loadDAEdFdx ()
1111 //
1112 // Purpose : Loads the F-vector contributions for a single
1113 // Neuron 3 instance.
1114 //
1115 // Special Notes : This is an algebraic constaint.
1116 //
1117 // Scope : public
1118 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1119 // Creation Date : 06/10/09
1120 //-----------------------------------------------------------------------------
1122 {
1123  bool bsuccess = true;
1124 
1125  N_LAS_Matrix * dFdxMatPtr = extData.dFdxMatrixPtr;
1126 
1127  (*dFdxMatPtr)[li_Pos][APosEquPosNodeOffset] += dkcl1F_dVin;
1128  (*dFdxMatPtr)[li_Pos][APosEquNextNodeOffset] += dkcl1F_dVs0;
1129 
1130  (*dFdxMatPtr)[li_Neg][ANegEquNegNodeOffset] += dkcl2F_dVout;
1131  (*dFdxMatPtr)[li_Neg][ANegEquLastNodeOffset] += dkcl2F_dVsn;
1132 
1133  for( int i=0; i<nSeg ; i++)
1134  {
1135  (*dFdxMatPtr)[li_Vol[i]][SegVEqnVpreOffset[i]] += segF_dVp[i];
1136  (*dFdxMatPtr)[li_Vol[i]][SegVEqnVsegOffset[i]] += segF_dV[i];
1137  (*dFdxMatPtr)[li_Vol[i]][SegVEqnVnexOffset[i]] += segF_dVn[i];
1138  (*dFdxMatPtr)[li_Vol[i]][SegVEqnNOffset[i]] += segF_dn[i];
1139  (*dFdxMatPtr)[li_Vol[i]][SegVEqnMOffset[i]] += segF_dm[i];
1140  (*dFdxMatPtr)[li_Vol[i]][SegVEqnHOffset[i]] += segF_dh[i];
1141 
1142  (*dFdxMatPtr)[li_nPro[i]][NEquVNodeOffset[i]] += dnF_dV[i];
1143  (*dFdxMatPtr)[li_nPro[i]][NEquNNodeOffset[i]] += dnF_dn[i];
1144  (*dFdxMatPtr)[li_mPro[i]][MEquVNodeOffset[i]] += dmF_dV[i];
1145  (*dFdxMatPtr)[li_mPro[i]][MEquMNodeOffset[i]] += dmF_dm[i];
1146  (*dFdxMatPtr)[li_hPro[i]][HEquVNodeOffset[i]] += dhF_dV[i];
1147  (*dFdxMatPtr)[li_hPro[i]][HEquHNodeOffset[i]] += dhF_dh[i];
1148  }
1149 
1150  return bsuccess;
1151 }
1152 
1153 //-----------------------------------------------------------------------------
1154 // Function : Instance::setIC
1155 // Purpose :
1156 // Special Notes :
1157 // Scope : public
1158 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1159 // Creation Date : 06/10/09
1160 //-----------------------------------------------------------------------------
1162 {
1163  bool bsuccess = true;
1164 
1165  return bsuccess;
1166 }
1167 
1168 //-----------------------------------------------------------------------------
1169 // Function : Instance::varTypes
1170 // Purpose :
1171 // Special Notes :
1172 // Scope : public
1173 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1174 // Creation Date : 06/10/09
1175 //-----------------------------------------------------------------------------
1176 void Instance::varTypes( std::vector<char> & varTypeVec )
1177 {
1178  //varTypeVec.resize(1);
1179  //varTypeVec[0] = 'I';
1180 }
1181 
1182 
1183 //-----------------------------------------------------------------------------
1184 // Function : Model::processParams
1185 // Purpose :
1186 // Special Notes :
1187 // Scope : public
1188 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1189 // Creation Date : 06/10/09
1190 //-----------------------------------------------------------------------------
1192 {
1193  return true;
1194 }
1195 
1196 //----------------------------------------------------------------------------
1197 // Function : Model::processInstanceParams
1198 // Purpose :
1199 // Special Notes :
1200 // Scope : public
1201 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1202 // Creation Date : 06/10/09
1203 //----------------------------------------------------------------------------
1205 {
1206  std::vector<Instance*>::iterator iter;
1207  std::vector<Instance*>::iterator first = instanceContainer.begin();
1208  std::vector<Instance*>::iterator last = instanceContainer.end();
1209 
1210  for (iter=first; iter!=last; ++iter)
1211  {
1212  (*iter)->processParams();
1213  }
1214 
1215  return true;
1216 }
1217 
1218 //-----------------------------------------------------------------------------
1219 // Function : Model::Model
1220 // Purpose : block constructor
1221 // Special Notes :
1222 // Scope : public
1223 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1224 // Creation Date : 06/10/09
1225 //-----------------------------------------------------------------------------
1227  const Configuration & configuration,
1228  const ModelBlock & MB,
1229  const FactoryBlock & factory_block)
1230  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
1231  rInt(0.0),
1232  radius(0.0),
1233  length(0.0),
1234  rIntGiven(false),
1235  radiusGiven(false),
1236  lengthGiven(false)
1237 {
1238 
1239  // Set params to constant default values:
1240  setDefaultParams ();
1241 
1242  // Set params according to .model line and constant defaults from metadata:
1243  setModParams (MB.params);
1244 
1245  // Set any non-constant parameter defaults:
1246  //if (!given("TNOM"))
1247  // tnom = getDeviceOptions().tnom;
1248 
1249  // Calculate any parameters specified as expressions:
1251 
1252  // calculate dependent (ie computed) params and check for errors:
1253 
1254  processParams ();
1255 }
1256 
1257 //-----------------------------------------------------------------------------
1258 // Function : Model::~Model
1259 // Purpose : destructor
1260 // Special Notes :
1261 // Scope : public
1262 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1263 // Creation Date : 06/10/09
1264 //-----------------------------------------------------------------------------
1266 {
1267  std::vector<Instance*>::iterator iter;
1268  std::vector<Instance*>::iterator first = instanceContainer.begin();
1269  std::vector<Instance*>::iterator last = instanceContainer.end();
1270 
1271  for (iter=first; iter!=last; ++iter)
1272  {
1273  delete (*iter);
1274  }
1275 
1276 }
1277 
1278 // additional Declarations
1279 
1280 //-----------------------------------------------------------------------------
1281 // Function : Model::printOutInstances
1282 // Purpose : debugging tool.
1283 // Special Notes :
1284 // Scope : public
1285 // Creator : Richard Schiek, Electrical and Microsytem Modeling
1286 // Creation Date : 06/10/09
1287 //-----------------------------------------------------------------------------
1288 std::ostream &Model::printOutInstances(std::ostream &os) const
1289 {
1290  std::vector<Instance*>::const_iterator iter;
1291  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1292  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1293 
1294  int i, isize;
1295  isize = instanceContainer.size();
1296 
1297  os << std::endl;
1298  os << "Number of Neuron instances: " << isize << std::endl;
1299  os << " name=\t\tmodelName\tParameters" << std::endl;
1300  for (i=0, iter=first; iter!=last; ++iter, ++i)
1301  {
1302  os << " " << i << ": " << (*iter)->getName() << "\t";
1303  os << getName();
1304  os << std::endl;
1305  }
1306 
1307  os << std::endl;
1308  return os;
1309 }
1310 
1311 //-----------------------------------------------------------------------------
1312 // Function : Model::forEachInstance
1313 // Purpose :
1314 // Special Notes :
1315 // Scope : public
1316 // Creator : David Baur
1317 // Creation Date : 2/4/2014
1318 //-----------------------------------------------------------------------------
1319 /// Apply a device instance "op" to all instances associated with this
1320 /// model
1321 ///
1322 /// @param[in] op Operator to apply to all instances.
1323 ///
1324 ///
1325 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1326 {
1327  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1328  op(*it);
1329 }
1330 
1331 
1332 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1333 {
1334 
1335  return new DeviceMaster<Traits>(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1336 }
1337 
1339 {
1341  .registerDevice("neuron", 3)
1342  .registerModelType("neuron", 3);
1343 }
1344 
1345 } // namespace Neuron3
1346 } // namespace Device
1347 } // namespace Xyce