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