Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_Synapse4.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_Synapse4.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Christina Warrender, SNL, Cognitive Modeling
33 //
34 // Creation Date : 10/12/11
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.53 $
40 //
41 // Revision Date : $Date: 2014/05/22 17:40:28 $
42 //
43 // Current Owner : $Author: erkeite $
44 //----------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 //#define Xyce_FullSynapseJac 1
48 
49 // ---------- Standard Includes ----------
50 // used to get time in seconds to seed random number generator.
51 #include<time.h>
52 
53 // ---------- Xyce Includes ----------
54 //
55 #include <N_DEV_Const.h>
56 #include <N_DEV_DeviceOptions.h>
57 #include <N_DEV_DeviceMaster.h>
58 #include <N_DEV_ExternData.h>
59 #include <N_DEV_MatrixLoadData.h>
60 #include <N_DEV_SolverState.h>
61 #include <N_DEV_Synapse4.h>
62 #include <N_DEV_Message.h>
63 #include <N_ERH_ErrorMgr.h>
64 
65 #include <N_DEV_Synapse.h>
66 
67 #include <N_LAS_Matrix.h>
68 #include <N_LAS_Vector.h>
69 
70 namespace Xyce {
71 namespace Device {
72 
73 
74 namespace Synapse4 {
75 
76 
78 {
79  // Set up configuration constants:
80 // Set up map for double precision variables:
81  p.addPar ("GMAX", 0.01, false, ParameterType::NO_DEP,
84  U_OHMM1, CAT_NONE, "Maximal Synaptic Conductance");
85 
86 }
87 
89 {
90  // Set up map for double precision variables:
91  p.addPar ("VTHRESH", 0.01, &Synapse4::Model::vThresh)
92  .setUnit(U_VOLT)
93  .setDescription("Presynaptic voltage spike threhsold");
94 
95  p.addPar ("DELAY", 0.001, &Synapse4::Model::delay)
96  .setUnit(U_SECOND)
97  .setDescription("Time delay between presynaptic signal and postsynaptic response");
98 
99  p.addPar ("GMAX", 0.01, &Synapse4::Model::gMax)
100  .setUnit(U_OHMM1)
101  .setDescription("Maximal Synaptic Conductance");
102 
103  p.addPar ("EREV", 0.0, &Synapse4::Model::eRev)
104  .setUnit(U_VOLT)
105  .setDescription("Postsynaptic Reversal Potential");
106 
107  p.addPar ("TAU1", 0.0001, &Synapse4::Model::tau1)
108  .setUnit(U_SECM1)
109  .setDescription("Rise time constant");
110 
111  p.addPar ("TAU2", 0.01, &Synapse4::Model::tau2)
112  .setUnit(U_SECM1)
113  .setDescription("Decay time constant");
114 }
115 
116 
117 
118 std::vector< std::vector<int> > Instance::jacStamp;
119 
120 // Class Instance
121 //-----------------------------------------------------------------------------
122 // Function : Instance::processParams
123 // Purpose :
124 // Special Notes :
125 // Scope : public
126 // Creator : Christina Warrender, SNL,
127 // Creation Date : 10/12/11
128 //-----------------------------------------------------------------------------
130 {
131  // initialization
132  respondTime = std::numeric_limits<double>::max( );
133  ready = true;
134  //active = false;
135 
136  return true;
137 }
138 
139 //-----------------------------------------------------------------------------
140 // Function : Instance::Instance
141 // Purpose : instance block constructor
142 // Special Notes :
143 // Scope : public
144 // Creator : Christina Warrender, SNL,
145 // Creation Date : 10/12/11
146 //-----------------------------------------------------------------------------
148  const Configuration & configuration,
149  const InstanceBlock & IB,
150  Model & Riter,
151  const FactoryBlock & factory_block)
152  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
153  model_(Riter),
154  li_Prev(-1),
155  li_Post(-1),
156  li_A0_store(-1),
157  li_B0_store(-1),
158  li_t0_store(-1),
159  li_store_dev_i(-1),
160 #ifdef Xyce_FullSynapseJac
161  APostEquPostNodeOffset(-1),
162  f_PostEquPostNodePtr(0),
163 #endif
164  ipost(0),
165  didVpost(0),
166  randInitialized(false)
167 {
168  numIntVars = 0; // A and B 2
169  numExtVars = 2; // presynaptic V and postsynaptic V
170  setNumStoreVars(3); // A0, B0, t0
172 
173  if( jacStamp.empty() )
174  {
175  jacStamp.resize(2);
176  jacStamp[0].resize(0); // presynaptic V not changed
177 #ifdef Xyce_FullSynapseJac
178  jacStamp[1].resize(1); // postsynaptic V depends on itself
179 #else
180  jacStamp[1].resize(0); // postsynaptic V depends on itself
181 #endif
182  }
183 
184 
185  // Set params to constant default values:
186  setDefaultParams ();
187 
188  // Set params according to instance line and constant defaults from metadata:
189  setParams (IB.params);
190 
191  // Set any non-constant parameter defaults:
192 
193  if (!gMaxGiven )
194  {
195  gMax = model_.gMax;
196  }
197 
198  // Calculate any parameters specified as expressions:
200 
201  // calculate dependent (ie computed) params and check for errors:
202  processParams ();
203 }
204 
205 //-----------------------------------------------------------------------------
206 // Function : Instance::~Instance
207 // Purpose : destructor
208 // Special Notes :
209 // Scope : public
210 // Creator : Christina Warrender, SNL,
211 // Creation Date : 10/12/11
212 //-----------------------------------------------------------------------------
214 {
215 }
216 
217 //-----------------------------------------------------------------------------
218 // Function : Instance::registerLIDs
219 // Purpose :
220 // Special Notes :
221 // Scope : public
222 // Creator : Christina Warrender, SNL,
223 // Creation Date : 10/12/11
224 //-----------------------------------------------------------------------------
225 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
226  const std::vector<int> & extLIDVecRef )
227 {
228  AssertLIDs(intLIDVecRef.size() == numIntVars);
229  AssertLIDs(extLIDVecRef.size() == numExtVars);
230 
231 #ifdef Xyce_DEBUG_DEVICE
232  if (getDeviceOptions().debugLevel > 0)
233  {
234  Xyce::dout() << std::endl << section_divider << std::endl;
235  Xyce::dout() << " SynapseInstance::registerLIDs" << std::endl;
236  Xyce::dout() << " name = " << getName() << std::endl;
237  }
238 #endif
239 
240  // copy over the global ID lists.
241  intLIDVec = intLIDVecRef;
242  extLIDVec = extLIDVecRef;
243 
244  li_Prev = extLIDVec[0];
245  li_Post = extLIDVec[1];
246 
247 #ifdef Xyce_DEBUG_DEVICE
248  if (getDeviceOptions().debugLevel > 0 )
249  {
250  Xyce::dout() << " li_Prev = " << li_Prev << std::endl;
251  Xyce::dout() << " li_Post = " << li_Post << std::endl;
252  }
253 #endif
254 
255  /*
256  li_AVar = intLIDVec[0];
257  li_BVar = intLIDVec[1];
258  */
259 
260 #ifdef Xyce_DEBUG_DEVICE
261  if (getDeviceOptions().debugLevel > 0 )
262  {
263  Xyce::dout() << section_divider << std::endl;
264  }
265 #endif
266 }
267 
268 //-----------------------------------------------------------------------------
269 // Function : Instance::getIntNameMap
270 // Purpose :
271 // Special Notes :
272 // Scope : public
273 // Creator : Christina Warrender, SNL, Cognitive Modeling
274 // Creation Date : 10/17/11
275 //-----------------------------------------------------------------------------
276 std::map<int,std::string> & Instance::getIntNameMap ()
277 {
278  return intNameMap;
279 }
280 
281 //-----------------------------------------------------------------------------
282 // Function : Instance::registerStoreLIDs
283 // Purpose :
284 // Special Notes :
285 // Scope : public
286 // Creator : Christina Warrender, SNL,
287 // Creation Date : 10/12/11
288 //-----------------------------------------------------------------------------
289 void Instance::registerStoreLIDs(const std::vector<int> & stoLIDVecRef )
290 {
291  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
292 
293  // copy over the global ID lists.
294  stoLIDVec = stoLIDVecRef;
295 
296  li_A0_store = stoLIDVec[0];
297  li_B0_store = stoLIDVec[1];
298  li_t0_store = stoLIDVec[2];
299  if( loadLeadCurrent )
300  {
301  li_store_dev_i = stoLIDVec[3];
302  }
303 
304 }
305 
306 //-----------------------------------------------------------------------------
307 // Function : Instance::getStoreNameMap
308 // Purpose :
309 // Special Notes :
310 // Scope : public
311 // Creator : Rich Schiek, SNL, Electrical Systems Modeling
312 // Creation Date : 08/01/2012
313 //-----------------------------------------------------------------------------
314 std::map<int,std::string> & Instance::getStoreNameMap()
315 {
316  // set up the internal name map, if it hasn't been already.
317  if (stateNameMap.empty ())
318  {
322  if( loadLeadCurrent )
323  {
325  }
326  }
327  return intNameMap;
328 }
329 
330 //-----------------------------------------------------------------------------
331 // Function : Instance::jacobianStamp
332 // Purpose :
333 // Special Notes :
334 // Scope : public
335 // Creator : Christina Warrender, SNL,
336 // Creation Date : 10/12/11
337 //-----------------------------------------------------------------------------
338 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
339 {
340  return jacStamp;
341 }
342 
343 //-----------------------------------------------------------------------------
344 // Function : Instance::registerJacLIDs
345 // Purpose :
346 // Special Notes :
347 // Scope : public
348 // Creator : Christina Warrender, SNL,
349 // Creation Date : 10/12/11
350 //-----------------------------------------------------------------------------
351 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
352 {
353  DeviceInstance::registerJacLIDs( jacLIDVec );
354 #ifdef Xyce_FullSynapseJac
355  APostEquPostNodeOffset = jacLIDVec[1][0];
356 #endif
357 }
358 
359 //-----------------------------------------------------------------------------
360 // Function : Instance::setupPointers
361 // Purpose :
362 // Special Notes :
363 // Scope : public
364 // Creator : Christina Warrender, SNL
365 // Creation Date : 10/12/11
366 //-----------------------------------------------------------------------------
368 {
369 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
370 #ifdef Xyce_FullSynapseJac
371  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
372  f_PostEquPostNodePtr = &(dFdx[li_Post][APostEquPostNodeOffset]);
373 #endif
374 #endif
375 }
376 
377 //-----------------------------------------------------------------------------
378 // Function : Instance::updateIntermediateVars
379 // Purpose : update intermediate variables for one synapse instance
380 // Special Notes :
381 // Scope : public
382 // Creator : Christina Warrender, SNL
383 // Creation Date : 10/12/11
384 //-----------------------------------------------------------------------------
386 {
387  bool bsuccess = true;
388 
389  double * lastSolVecPtr = extData.lastSolVectorRawPtr;
390  double * stoVector = extData.nextStoVectorRawPtr;
391  double * lastStoVec = extData.lastStoVectorRawPtr;
392 
393  // initialized random number generator if needed
394  if( !randInitialized )
395  {
396  if( getDeviceOptions().randomSeed != 0 )
397  {
398  devSupport.SetSeed( getDeviceOptions().randomSeed );
399  }
400  else
401  {
402  unsigned int aSeed = static_cast<unsigned int>(time( NULL ) ) ;
403  devSupport.SetSeed( aSeed );
404  }
405  randInitialized=true;
406  }
407 
408  // This check need to
409  // Check for presynaptic spike start, set time to respond
410  double vPre = lastSolVecPtr[li_Prev];
411  double vPost = lastSolVecPtr[li_Post];
412  double time = getSolverState().currTime;
413  double vThresh = model_.vThresh;
414  double delay = model_.delay;
415  if (ready)
416  {
417  if (vPre > vThresh)
418  {
419  ready=false;
420  respondTime = time + delay;
421  }
422  }
423  else // already had spike start, looking for end
424  {
425  if (vPre < vThresh)
426  {
427  ready=true;
428  }
429  }
430 
431  // only need to update state variables and synaptic current when synapse active
432  // disabling testing for this because determining the point at which the synaptic current
433  // becomes negligible is somewhat problematic, and there don't appear to be significant savings
434  // from avoiding loads when synapse is inactive
435  //if (active)
436  {
437  // handle decay of A and B
438  double tau1 = model_.tau1;
439  double tau2 = model_.tau2;
440 
441  double t0 = stoVector[li_t0_store];
442  double Anow = stoVector[li_A0_store] * exp( - ( time - t0 ) / tau1 );
443  double Bnow = stoVector[li_B0_store] * exp( - ( time - t0 ) / tau2 );
444 
445  // set up variables for load methods
446  // current equation is the same whether we're responding to spike or not,
447  // assuming current A and B values set appropriately above
448  // ipost = (B-A)*(V-Erev)
449 
450  double eRev = model_.eRev;
451  double cond = Bnow-Anow;
452  ipost = cond*(vPost-eRev);
453  didVpost = cond;
454 
455 #ifdef Xyce_DEBUG_DEVICE
456  if (getDeviceOptions().debugLevel > 0)
457  {
458  Xyce::dout() << std::endl << section_divider << std::endl;
459  Xyce::dout() << " SynapseInstance::updateIntermediateVars" << std::endl;
460  Xyce::dout() << "Anow: " << Anow << std::endl;
461  Xyce::dout() << "Bnow: " << Bnow << std::endl;
462  Xyce::dout() << "vPost: " << vPost << std::endl;
463  Xyce::dout() << "eRev: " << eRev << std::endl;
464  Xyce::dout() << "ipost: " << ipost << std::endl;
465  Xyce::dout() << "didVpost: " << didVpost << std::endl;
466  }
467 #endif
468 
469  } // end if synapse active
470 
471  return bsuccess;
472 }
473 
474 //-----------------------------------------------------------------------------
475 // Function : Instance::updatePrimaryState
476 // Purpose :
477 // Special Notes :
478 // Scope : public
479 // Creator : Christina Warrender, SNL,
480 // Creation Date : 10/12/11
481 //-----------------------------------------------------------------------------
483 {
484  bool bsuccess = updateIntermediateVars();
485  return bsuccess;
486 }
487 
488 //-----------------------------------------------------------------------------
489 // Function : Instance::updateSecondaryState
490 // Purpose :
491 // Special Notes :
492 // Scope : public
493 // Creator : Christina Warrender, SNL,
494 // Creation Date : 10/12/11
495 //-----------------------------------------------------------------------------
497 {
498  return true;
499 }
500 
501 //-----------------------------------------------------------------------------
502 // Function : Instance::loadDAEQVector
503 //
504 // Purpose : Loads the Q-vector contributions for a single
505 // Synapse4
506 //
507 // Special Notes : The "Q" vector is part of a standard DAE formalism in
508 // which the system of equations is represented as:
509 //
510 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
511 //
512 // The "Q" vector contains charges and fluxes, mostly.
513 // However, it is ordered like the solution vector, and as
514 // it is part of the KCL formulation, the terms in Q will
515 // actually be *sums* of charges, rather than single
516 // distinct charges.
517 //
518 // Scope : public
519 // Creator : Christina Warrender, SNL,
520 // Creation Date : 10/12/11
521 //-----------------------------------------------------------------------------
523 {
524  return true;
525 }
526 //-----------------------------------------------------------------------------
527 // Function : Instance::loadDAEFVector
528 //
529 // Purpose : Loads the F-vector contributions for a single
530 // Synapse4 instance.
531 //
532 // Special Notes : This is an algebraic constaint, and as such the Synapse4
533 // does make a contribution to it.
534 //
535 // Scope : public
536 // Creator : Christina Warrender, SNL,
537 // Creation Date : 10/12/11
538 //-----------------------------------------------------------------------------
540 {
541  N_LAS_Vector * fVecPtr = extData.daeFVectorPtr;
542  (*fVecPtr)[li_Prev] += 0.0;
543  (*fVecPtr)[li_Post] += ipost;
544  if( loadLeadCurrent )
545  {
546  double * stoVec = extData.nextStoVectorRawPtr;
547  stoVec[li_store_dev_i] = ipost;
548  }
549  return true;
550 }
551 
552 //-----------------------------------------------------------------------------
553 // Function : Instance::loadDAEdQdx
554 //
555 // Purpose : Loads the dQdx-matrix contributions for a single
556 // Synapse4 instance.
557 //
558 // Special Notes : The "Q" vector is part of a standard DAE formalism in
559 // which the system of equations is represented as:
560 //
561 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
562 //
563 // The "Q" vector contains charges and fluxes, mostly.
564 // However, it is ordered like the solution vector, and as
565 // it is part of the KCL formulation, the terms in Q will
566 // actually be *sums* of charges, rather than single
567 // distinct charges.
568 //
569 // Scope : public
570 // Creator : Christina Warrender, SNL,
571 // Creation Date : 10/12/11
572 //-----------------------------------------------------------------------------
574 {
575  return true;
576 }
577 
578 //-----------------------------------------------------------------------------
579 // Function : Instance::loadDAEdFdx ()
580 //
581 // Purpose : Loads the F-vector contributions for a single
582 // Synapse4 instance.
583 //
584 // Special Notes : This is an algebraic constaint, and as such the Synapse4
585 // does make a contribution to it.
586 //
587 // Scope : public
588 // Creator : Christina Warrender, SNL,
589 // Creation Date : 10/12/11
590 //-----------------------------------------------------------------------------
592 {
593 #ifdef Xyce_FullSynapseJac
594  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
595  dFdx[li_Post][APostEquPostNodeOffset] += didVpost;
596 #endif
597  return true;
598 }
599 
600 //-----------------------------------------------------------------------------
601 // Function : InstanceInstance::outputPlotFiles
602 // Purpose : If requested by the user output all the variables
603 // associated with the population
604 // Special Notes : We're actually using this method not for output, but because
605 // it's called after the system has converged. In this case,
606 // that let us mark the end of handling a presynaptic event.
607 // Scope : public
608 // Creator : Christina Warrender, SNL, Cognitive Modeling
609 // Creation Date : 10/25/2011
610 //-----------------------------------------------------------------------------
612 {
613  bool bsuccess = true;
614 
615  // cew 11/3/11: changing this back to just storing A0 and B0 for updateIntermediateVars
616  // to use in calculating A, B, and ipost
617  // But when incrementing A0 (B0), current value of A (B) must be used.
618 
619  double time = getSolverState().currTime;
620  //N_LAS_Vector * staVector = extData.nextStaVectorPtr;
621  double * stoVector = extData.nextStoVectorRawPtr;
622  if (time >= respondTime)
623  {
624  //Xyce::dout() << "Instance::outputPlotFiles() adjusting A0, B0 and t0 = " << getSolverState().currTime << std::endl;
625  // succesfully processed a step, so adjust the next
626  // respondTime to distant future
627  respondTime = std::numeric_limits<double>::max( );
628  //active = true;
629 
630  // now we also update the A0, B0 and t0 in the state vector
631  double factor = model_.factor;
632  double deltaAB = factor*gMax;
633  double tau1 = model_.tau1;
634  double tau2 = model_.tau2;
635  double t0 = stoVector[li_t0_store];
636  double Anow = stoVector[li_A0_store] * exp( - ( time - t0 ) / tau1 );
637  double Bnow = stoVector[li_B0_store] * exp( - ( time - t0 ) / tau2 );
638  stoVector[li_A0_store] = Anow + deltaAB;
639  stoVector[li_B0_store] = Bnow + deltaAB;
640  stoVector[li_t0_store] = getSolverState().currTime;
641  //Xyce::dout() << "A: " << (*staVector)[li_A0_state] << " B: " << (*staVector)[li_B0_state] << std::endl;
642  }
643 
644 /* disabling this because determining the point at which the synaptic current becomes negligible
645  is somewhat problematic, and there don't appear to be significant savings from avoiding loads
646  when synapse is inactive
647  if (active)
648  {
649  // determine when we can stop updating synaptic current, when it's negligible
650  // can't use magnitude of current, because it starts off small initially
651  // instead, determine whether time since last spike is greater than reasonable multiple of
652  // larger time constant
653  if ( (time-(*staVector)[li_t0_state])>3.0*model_.maxtau )
654  {
655  active = false;
656  ipost = 0.0;
657  didVpost = 0.0;
658  }
659  }
660 */
661 
662  return bsuccess;
663 }
664 
665 //-----------------------------------------------------------------------------
666 // Function : Instance::updateTemperature
667 // Purpose :
668 // Special Notes :
669 // Scope : public
670 // Creator : Tom Russo, Component Information and Models
671 // Creation Date : 10/12/11
672 //-----------------------------------------------------------------------------
673 bool Instance::updateTemperature ( const double & temp_tmp)
674 {
675  bool bsuccess = true;
676  return bsuccess;
677 }
678 
679 //-----------------------------------------------------------------------------
680 // Function : Model::processParams
681 // Purpose :
682 // Special Notes :
683 // Scope : public
684 // Creator : Christina Warrender, SNL,
685 // Creation Date : 10/12/11
686 //-----------------------------------------------------------------------------
688 {
689  // initialize variables needed to calculate synaptic dynamics
690  if (tau1/tau2 > .9999) {
691  tau1 = .9999*tau2;
692  }
693  tp = (tau1*tau2)/(tau2 - tau1) * log(tau2/tau1);
694  factor = -exp(-tp/tau1) + exp(-tp/tau2);
695  factor = 1/factor;
696  maxtau = (tau1>tau2)?tau1:tau2;
697 
698  return true;
699 }
700 
701 //----------------------------------------------------------------------------
702 // Function : Model::processInstanceParams
703 // Purpose :
704 // Special Notes :
705 // Scope : public
706 // Creator : Dave Shirely, PSSI
707 // Creation Date : 10/12/11
708 //----------------------------------------------------------------------------
710 {
711 
712  std::vector<Instance*>::iterator iter;
713  std::vector<Instance*>::iterator first = instanceContainer.begin();
714  std::vector<Instance*>::iterator last = instanceContainer.end();
715 
716  for (iter=first; iter!=last; ++iter)
717  {
718  (*iter)->processParams();
719  }
720 
721  return true;
722 }
723 
724 //-----------------------------------------------------------------------------
725 // Function : Model::Model
726 // Purpose : model block constructor
727 // Special Notes :
728 // Scope : public
729 // Creator : Christina Warrender, SNL,
730 // Creation Date : 10/12/11
731 //-----------------------------------------------------------------------------
733  const Configuration & configuration,
734  const ModelBlock & MB,
735  const FactoryBlock & factory_block)
736  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
737  vThresh(0.0),
738  delay(0.0),
739  gMax(0.0),
740  eRev(0.0),
741  tau1(0.0),
742  tau2(0.0)
743 {
744 
745  // Set params to constant default values:
746  setDefaultParams ();
747 
748  // Set params according to .model line and constant defaults from metadata:
749  setModParams (MB.params);
750 
751  // Set any non-constant parameter defaults:
752 
753  // Calculate any parameters specified as expressions:
755 
756  // calculate dependent (ie computed) params and check for errors:
757  processParams();
758 }
759 
760 //-----------------------------------------------------------------------------
761 // Function : Model::~Model
762 // Purpose : destructor
763 // Special Notes :
764 // Scope : public
765 // Creator : Christina Warrender, SNL,
766 // Creation Date : 10/12/11
767 //-----------------------------------------------------------------------------
769 {
770  std::vector<Instance*>::iterator iter;
771  std::vector<Instance*>::iterator first = instanceContainer.begin();
772  std::vector<Instance*>::iterator last = instanceContainer.end();
773 
774  for (iter=first; iter!=last; ++iter)
775  {
776  delete (*iter);
777  }
778 }
779 
780 //-----------------------------------------------------------------------------
781 // Function : Model::printOutInstances
782 // Purpose : debugging tool.
783 // Special Notes :
784 // Scope : public
785 // Creator : Christina Warrender, SNL,
786 // Creation Date : 10/12/11
787 //-----------------------------------------------------------------------------
788 std::ostream &Model::printOutInstances(std::ostream &os) const
789 {
790  std::vector<Instance*>::const_iterator iter;
791  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
792  std::vector<Instance*>::const_iterator last = instanceContainer.end();
793 
794  int i,isize;
795  isize = instanceContainer.size();
796  os << std::endl;
797  os << "Number of Synapse4 Instances: " << isize << std::endl;
798  os << " name model name Parameters" << std::endl;
799  for (i=0, iter=first; iter!=last; ++iter, ++i)
800  {
801  os << " " << i << ": " << (*iter)->getName() << "\t";
802  os << getName();
803  os << std::endl;
804  }
805 
806  os << std::endl;
807  return os;
808 }
809 
810 //-----------------------------------------------------------------------------
811 // Function : Model::forEachInstance
812 // Purpose :
813 // Special Notes :
814 // Scope : public
815 // Creator : David Baur
816 // Creation Date : 2/4/2014
817 //-----------------------------------------------------------------------------
818 /// Apply a device instance "op" to all instances associated with this
819 /// model
820 ///
821 /// @param[in] op Operator to apply to all instances.
822 ///
823 ///
824 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
825 {
826  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
827  op(*it);
828 }
829 
830 
831 //-----------------------------------------------------------------------------
832 // Function : Master::updateState
833 // Purpose :
834 // Special Notes :
835 // Scope : public
836 // Creator : Christina Warrender, SNL, Cognitive Modeling
837 // Creation Date : 07/18/12
838 //-----------------------------------------------------------------------------
839 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
840 {
841  if( getSolverState().dcopFlag )
842  {
843  // no synaptic activity during dcop
844  return true;
845  }
846 
847  bool bsuccess = true;
848 
849 #ifdef _OMP
850 #pragma omp parallel for reduction (&&:bsuccess)
851 #endif
852 
853  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
854  {
855  bool tmpBool = (*it)->updateIntermediateVars(); // skipping call to updatePrimaryState
856  bsuccess = bsuccess && tmpBool;
857  }
858 
859  return bsuccess;
860 }
861 
862 //-----------------------------------------------------------------------------
863 // Function : Master::updateSecondaryState
864 // Purpose :
865 // Special Notes :
866 // Scope : public
867 // Creator : Christina Warrender, SNL, Cognitive Modeling
868 // Creation Date : 7/18/12
869 //-----------------------------------------------------------------------------
870 bool Master::updateSecondaryState (double * staDerivVec, double *stoVec)
871 {
872  // not used for this device
873  return true;
874 }
875 
876 
877 //-----------------------------------------------------------------------------
878 // Function : Master::loadDAEVectors
879 // Purpose :
880 // Special Notes :
881 // Scope : public
882 // Creator : Christina Warrender, SNL, Cognitive Modeling
883 // Creation Date : 07/16/12
884 //-----------------------------------------------------------------------------
885 bool Master::loadDAEVectors(double * solVec, double * fVec, double * qVec, double * bVec, double * storeLeadF, double * storeLeadQ)
886 {
887  if( getSolverState().dcopFlag )
888  {
889  // no synaptic activity during dcop
890  return true;
891  }
892 
893  bool bsuccess = true;
894 
895  // We don't need Q loads for this synapse device at all
896  // Only need to do F loads if there's a nonzero synaptic current
897  // disabling testing for the latter because determining the point at which the synaptic current
898  // becomes negligible is somewhat problematic, and there don't appear to be significant savings
899  // from avoiding loads when synapse is inactive
900 
901  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
902  {
903  bool tmpBool = (*it)->loadDAEFVector();
904  bsuccess = bsuccess && tmpBool;
905  }
906 
907  return bsuccess;
908 }
909 
910 //-----------------------------------------------------------------------------
911 // Function : Master::loadDAEMatrices
912 // Purpose :
913 // Special Notes :
914 // Scope : public
915 // Creator : Christina Warrender, SNL, Cognitive Modeling
916 // Creation Date : 07/16/12
917 //-----------------------------------------------------------------------------
918 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
919 {
920  if( getSolverState().dcopFlag )
921  {
922  // no synaptic activity during dcop
923  return true;
924  }
925 
926  bool bsuccess = true;
927 
928  // We don't need Q loads for this synapse device at all
929  // Only need to do F loads if there's a nonzero synaptic current
930  // disabling testing for the latter because determining the point at which the synaptic current
931  // becomes negligible is somewhat problematic, and there don't appear to be significant savings
932  // from avoiding loads when synapse is inactive
933 
934  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
935  {
936  bool tmpBool = (*it)->loadDAEdFdx();
937  bsuccess = bsuccess && tmpBool;
938  }
939 
940  return bsuccess;
941 }
942 
943 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
944 {
945 
946  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
947 }
948 
950 {
952  .registerDevice("synapse", 4)
953  .registerModelType("synapse", 4);
954 }
955 
956 } // namespace Synapse4
957 } // namespace Device
958 } // namespace Xyce