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.48 $
40 //
41 // Revision Date : $Date: 2014/05/19 15:49:14 $
42 //
43 // Current Owner : $Author: dgbaur $
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  {
381  if( loadLeadCurrent )
382  {
384  }
385  }
386 
387  return storeNameMap;
388 }
389 
390 //-----------------------------------------------------------------------------
391 // Function : Instance::jacobianStamp
392 // Purpose :
393 // Special Notes :
394 // Scope : public
395 // Creator : Christina Warrender, SNL,
396 // Creation Date : 10/12/11
397 //-----------------------------------------------------------------------------
398 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
399 {
400  return jacStamp;
401 }
402 
403 //-----------------------------------------------------------------------------
404 // Function : Instance::registerJacLIDs
405 // Purpose :
406 // Special Notes :
407 // Scope : public
408 // Creator : Christina Warrender, SNL,
409 // Creation Date : 10/12/11
410 //-----------------------------------------------------------------------------
411 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
412 {
413  DeviceInstance::registerJacLIDs( jacLIDVec );
414 #ifdef Xyce_FullSynapseJac
415  APostEquPostNodeOffset = jacLIDVec[1][0];
416 #endif
417 }
418 
419 //-----------------------------------------------------------------------------
420 // Function : Instance::setupPointers
421 // Purpose :
422 // Special Notes :
423 // Scope : public
424 // Creator : Christina Warrender, SNL
425 // Creation Date : 10/12/11
426 //-----------------------------------------------------------------------------
428 {
429 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
430 #ifdef Xyce_FullSynapseJac
431  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
432  f_PostEquPostNodePtr = &(dFdx[li_Post][APostEquPostNodeOffset]);
433 #endif
434 #endif
435 }
436 
437 //-----------------------------------------------------------------------------
438 // Function : Instance::updateIntermediateVars
439 // Purpose : update intermediate variables for one diode instance
440 // Special Notes :
441 // Scope : public
442 // Creator : Christina Warrender, SNL
443 // Creation Date : 10/12/11
444 //-----------------------------------------------------------------------------
446 {
447  bool bsuccess = true;
448 
449  double * lastSolVecPtr = extData.lastSolVectorRawPtr;
450  double * stoVec = extData.nextStoVectorRawPtr;
451  double * lastStoVec = extData.lastStoVectorRawPtr;
452 
453  double vPre = lastSolVecPtr[li_Prev];
454  double vPost = lastSolVecPtr[li_Post];
455 
456  // initialized random number generator if needed
457  if( !randInitialized )
458  {
459  if( getDeviceOptions().randomSeed != 0 )
460  {
461  devSupport.SetSeed( getDeviceOptions().randomSeed );
462  }
463  else
464  {
465  unsigned int aSeed = static_cast<unsigned int>(time( NULL ) ) ;
466  devSupport.SetSeed( aSeed );
467  }
468  randInitialized=true;
469  }
470 
471  // to do: Need to adjust this conditional to do this same initialization
472  // if the dcop is being skipped and this is the first iteration.
473  if( getSolverState().dcopFlag )
474  {
475  // no firing during DCOP, so postsynaptic current is 0 and unchanging
476  ipost = 0.0;
477  didVpost = 0.0;
481  stoVec[li_A0_store] = 0.0;
482  stoVec[li_B0_store] = 0.0;
483  stoVec[li_VL1_store] = vPost;
484  stoVec[li_VL2_store] = vPost;
485  stoVec[li_VL3_store] = 0.0;
486  }
487  else
488  {
489  // Check for presynaptic spikes, set time to respond
490  double time = getSolverState().currTime;
491  double vThresh = model_.vThresh;
492  double delay = model_.delay;
493  if (ready)
494  {
495  if (vPre > vThresh)
496  {
497  ready=false;
498  respondTime = time + delay;
499  // check transmissionProbability to see if current is transmitted
501  if( transmissionProbability < 1.0 )
502  {
503  double arand = devSupport.getRandomPerturbation(); // get a number from [0, 1)
504  if( arand > transmissionProbability )
505  {
507  }
508  }
509  }
510  }
511  else // already had spike start, looking for end
512  {
513  // Need to improve the logic here so that no only is the pre snyapse going down (vPre < vThresh),
514  // but synapse must be done with its work. (tau1 + tau2) after delay?
515  if( (vPre < vThresh) && ((time - lastStoVec[li_t0_store]) > ( model_.tau1 + model_.tau2 )))
516  {
517  ready=true;
518  }
519  }
520 
521  // handle decay of A and B
522  double tau1 = model_.tau1;
523  double tau2 = model_.tau2;
524 
525  double t0 = stoVec[li_t0_store];
526  double Anow = stoVec[li_A0_store] * exp( - ( time - t0 ) / tau1 );
527  double Bnow = stoVec[li_B0_store] * exp( - ( time - t0 ) / tau2 );
528  double vl1Now = stoVec[li_VL1_store];
529  double vl2Now = stoVec[li_VL2_store];
530  double vl3Now = stoVec[li_VL3_store];
532 
533  // calculate update to synaptic weight
534  synapticWeightUpdate = 0.0;
535  // only if the synapse is transmitting should be update the synaptic weight.
536  // transmissionFactor is only 0 or 1
537  if( transmissionFactor == 1 )
538  {
540  {
541  // weight in in range so update may be non zero. Check LTD and LTP terms.
542  if( (vPre > model_.sParam) && (vl1Now > model_.rParam) )
543  {
544  synapticWeightUpdate += -(model_.aLTD) * (vl1Now - model_.rParam);
545  }
546  if( (vPost > model_.sParam) && (vl2Now > model_.rParam) )
547  {
548  synapticWeightUpdate += (model_.aLTP) * vl3Now * (vPost - model_.sParam) * (vl2Now - model_.rParam);
549  }
550  }
551 
552  double wMin = model_.wMin;
553  double wMax = model_.wMax;
554 
555  // enforce min/max bounds on weight
557  {
559  }
560  else if (synapticWeight+synapticWeightUpdate < wMin)
561  {
563  }
564  }
565 
566 
567  vl1Update = getSolverState().currTimeStep * (vPost - vl1Now) / model_.vL1tau1;
568  vl2Update = getSolverState().currTimeStep * (vPost - vl2Now) / model_.vL2tau2;
569  if( vPre > model_.sParam )
570  {
571  vl3Update = getSolverState().currTimeStep * (1.0 - vl3Now) / model_.vL3tau3;
572  }
573  else
574  {
576  }
577 
578 #ifdef Xyce_DEBUG_DEVICE
579  if (getDeviceOptions().debugLevel > 0)
580  {
581  Xyce::dout() << std::endl << section_divider << std::endl;
582  Xyce::dout() << " SynapseInstance::updateIntermediateVars" << std::endl;
583  Xyce::dout() << "Anow: " << Anow << std::endl;
584  Xyce::dout() << "Bnow: " << Bnow << std::endl;
585  }
586 #endif
587 
588  // set up variables for load methods
589 
590  // current equation is the same whether we're responding to spike or not,
591  // assuming current A and B values set appropriately above
592  // ipost = (B-A)*(V-Erev)
593  double eRev = model_.eRev;
594  //ipost = (synapticWeight + synapticWeightUpdate) * (Bnow-Anow)*(vPost-eRev);
595  ipost = transmissionFactor * synapticWeight * (Bnow-Anow)*(vPost-eRev);
596 
597  //didVpost = (synapticWeight + synapticWeightUpdate) * (Bnow - Anow);
598  // update synaptic weight after time steps is successful.
599  didVpost = synapticWeight * (Bnow - Anow);
600 
601 #ifdef Xyce_DEBUG_DEVICE
602  if (getDeviceOptions().debugLevel > 0)
603  {
604  Xyce::dout() << std::endl << section_divider << std::endl;
605  Xyce::dout() << "vPost: " << vPost << std::endl;
606  Xyce::dout() << "eRev: " << eRev << std::endl;
607  Xyce::dout() << "weight: " << synapticWeight << std::endl;
608  Xyce::dout() << "weight update: " << synapticWeightUpdate << std::endl;
609  Xyce::dout() << "ipost: " << ipost << std::endl;
610  Xyce::dout() << "didVpost: " << didVpost << std::endl;
611  }
612 #endif
613 
614  } // end else (!getSolverState().dcopFlag)
615 
616  return bsuccess;
617 }
618 
619 //-----------------------------------------------------------------------------
620 // Function : Instance::updatePrimaryState
621 // Purpose :
622 // Special Notes :
623 // Scope : public
624 // Creator : Christina Warrender, SNL,
625 // Creation Date : 10/12/11
626 //-----------------------------------------------------------------------------
628 {
629  bool bsuccess = updateIntermediateVars();
630  return bsuccess;
631 }
632 
633 //-----------------------------------------------------------------------------
634 // Function : Instance::updateSecondaryState
635 // Purpose :
636 // Special Notes :
637 // Scope : public
638 // Creator : Christina Warrender, SNL,
639 // Creation Date : 10/12/11
640 //-----------------------------------------------------------------------------
642 {
643  return true;
644 }
645 
646 //-----------------------------------------------------------------------------
647 // Function : Instance::loadDAEQVector
648 //
649 // Purpose : Loads the Q-vector contributions for a single
650 // Synapse4
651 //
652 // Special Notes : The "Q" vector is part of a standard DAE formalism in
653 // which the system of equations is represented as:
654 //
655 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
656 //
657 // The "Q" vector contains charges and fluxes, mostly.
658 // However, it is ordered like the solution vector, and as
659 // it is part of the KCL formulation, the terms in Q will
660 // actually be *sums* of charges, rather than single
661 // distinct charges.
662 //
663 // Scope : public
664 // Creator : Christina Warrender, SNL,
665 // Creation Date : 10/12/11
666 //-----------------------------------------------------------------------------
668 {
669  return true;
670 }
671 //-----------------------------------------------------------------------------
672 // Function : Instance::loadDAEFVector
673 //
674 // Purpose : Loads the F-vector contributions for a single
675 // Synapse3 instance.
676 //
677 // Special Notes : This is an algebraic constaint, and as such the Synapse3
678 // does make a contribution to it.
679 //
680 // Scope : public
681 // Creator : Christina Warrender, SNL,
682 // Creation Date : 10/12/11
683 //-----------------------------------------------------------------------------
685 {
686  N_LAS_Vector * fVecPtr = extData.daeFVectorPtr;
687  (*fVecPtr)[li_Prev] += 0.0;
688  (*fVecPtr)[li_Post] += ipost;
689 
690  if( loadLeadCurrent )
691  {
692  double * stoVec = extData.nextStoVectorRawPtr;
693  stoVec[li_store_dev_i] = ipost;
694  }
695 
696  return true;
697 }
698 
699 //-----------------------------------------------------------------------------
700 // Function : Instance::loadDAEdQdx
701 //
702 // Purpose : Loads the dQdx-matrix contributions for a single
703 // Synapse3 instance.
704 //
705 // Special Notes : The "Q" vector is part of a standard DAE formalism in
706 // which the system of equations is represented as:
707 //
708 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
709 //
710 // The "Q" vector contains charges and fluxes, mostly.
711 // However, it is ordered like the solution vector, and as
712 // it is part of the KCL formulation, the terms in Q will
713 // actually be *sums* of charges, rather than single
714 // distinct charges.
715 //
716 // Scope : public
717 // Creator : Christina Warrender, SNL,
718 // Creation Date : 10/12/11
719 //-----------------------------------------------------------------------------
721 {
722  return true;
723 }
724 
725 //-----------------------------------------------------------------------------
726 // Function : Instance::loadDAEdFdx ()
727 //
728 // Purpose : Loads the F-vector contributions for a single
729 // Synapse3 instance.
730 //
731 // Special Notes : This is an algebraic constaint, and as such the Synapse3
732 // does make a contribution to it.
733 //
734 // Scope : public
735 // Creator : Christina Warrender, SNL,
736 // Creation Date : 10/12/11
737 //-----------------------------------------------------------------------------
739 {
740 #ifdef Xyce_FullSynapseJac
741  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
742  dFdx[li_Post][APostEquPostNodeOffset] += didVpost;
743 #endif
744  return true;
745 }
746 
747 //-----------------------------------------------------------------------------
748 // Function : InstanceInstance::outputPlotFiles
749 // Purpose : If requested by the user output all the variables
750 // associated with the population
751 // Special Notes : We're actually using this method not for output, but because
752 // it's called after the system has converged. In this case,
753 // that let us mark the end of handling a presynaptic event.
754 // Scope : public
755 // Creator : Christina Warrender, SNL, Cognitive Modeling
756 // Creation Date : 10/25/2011
757 //-----------------------------------------------------------------------------
759 {
760  bool bsuccess = true;
761 
762  // cew 11/3/11: changing this back to just storing A0 and B0 for updateIntermediateVars
763  // to use in calculating A, B, and ipost
764  // But when incrementing A0 (B0), current value of A (B) must be used.
765 
766  double time = getSolverState().currTime;
767  double * stoVec = extData.nextStoVectorRawPtr;
768 
769  if (time >= respondTime)
770  {
771  //Xyce::dout() << "Instance::outputPlotFiles() adjusting A0, B0 and t0 = " << getSolverState().currTime << ", " << respondTime << std::endl;
772  // succesfully processed a step, so adjust the next
773  // respondTime to distant future
774  respondTime = std::numeric_limits<double>::max( );
775 
776  // now we also update the A0, B0 and t0 in the state vector
777  double factor = model_.factor;
778  double deltaAB = factor*gMax;
779  double tau1 = model_.tau1;
780  double tau2 = model_.tau2;
781 
782  double t0 = stoVec[li_t0_store];
783  double Anow = stoVec[li_A0_store] * exp( - ( time - t0 ) / tau1 );
784  double Bnow = stoVec[li_B0_store] * exp( - ( time - t0 ) / tau2 );
785  stoVec[li_A0_store] = Anow + deltaAB;
786  stoVec[li_B0_store] = Bnow + deltaAB;
787  stoVec[li_t0_store] = getSolverState().currTime;
788  } // end if time >= respondTime
789 
791  stoVec[li_VL1_store] += vl1Update;
792  stoVec[li_VL2_store] += vl2Update;
793  stoVec[li_VL3_store] += vl3Update;
794 
795 #ifdef Xyce_DEBUG_DEVICE
796  if (getDeviceOptions().debugLevel > 0)
797  {
798  Xyce::dout() << std::endl << section_divider << std::endl;
799  Xyce::dout() << " SynapseInstance::outputPlotFiles" << std::endl;
800  Xyce::dout() << "time: " << getSolverState().currTime << std::endl;
801  Xyce::dout() << "weight in store: " << stoVec[li_weight_store] << std::endl;
802  }
803 #endif
804 
805 
806  return bsuccess;
807 }
808 
809 //-----------------------------------------------------------------------------
810 // Function : Instance::updateTemperature
811 // Purpose :
812 // Special Notes :
813 // Scope : public
814 // Creator : Tom Russo, Component Information and Models
815 // Creation Date : 10/12/11
816 //-----------------------------------------------------------------------------
817 bool Instance::updateTemperature ( const double & temp_tmp)
818 {
819  bool bsuccess = true;
820  return bsuccess;
821 }
822 
823 //-----------------------------------------------------------------------------
824 // Function : Model::processParams
825 // Purpose :
826 // Special Notes :
827 // Scope : public
828 // Creator : Christina Warrender, SNL,
829 // Creation Date : 10/12/11
830 //-----------------------------------------------------------------------------
832 {
833  // initialize variables needed to calculate synaptic dynamics
834  if (tau1/tau2 > .9999) {
835  tau1 = .9999*tau2;
836  }
837  tp = (tau1*tau2)/(tau2 - tau1) * log(tau2/tau1);
838  factor = -exp(-tp/tau1) + exp(-tp/tau2);
839  factor = 1/factor;
840 
841  return true;
842 }
843 
844 //----------------------------------------------------------------------------
845 // Function : Model::processInstanceParams
846 // Purpose :
847 // Special Notes :
848 // Scope : public
849 // Creator : Dave Shirely, PSSI
850 // Creation Date : 10/12/11
851 //----------------------------------------------------------------------------
853 {
854 
855  std::vector<Instance*>::iterator iter;
856  std::vector<Instance*>::iterator first = instanceContainer.begin();
857  std::vector<Instance*>::iterator last = instanceContainer.end();
858 
859  for (iter=first; iter!=last; ++iter)
860  {
861  (*iter)->processParams();
862  }
863 
864  return true;
865 }
866 
867 //-----------------------------------------------------------------------------
868 // Function : Model::Model
869 // Purpose : model block constructor
870 // Special Notes :
871 // Scope : public
872 // Creator : Christina Warrender, SNL,
873 // Creation Date : 10/12/11
874 //-----------------------------------------------------------------------------
876  const Configuration & configuration,
877  const ModelBlock & MB,
878  const FactoryBlock & factory_block)
879  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
880  vThresh(0.0),
881  delay(0.0),
882  gMax(0.0),
883  eRev(0.0),
884  tau1(0.0),
885  tau2(0.0)
886 {
887 
888  // Set params to constant default values:
889  setDefaultParams ();
890 
891  // Set params according to .model line and constant defaults from metadata:
892  setModParams (MB.params);
893 
894  // Set any non-constant parameter defaults:
895 
896  // Calculate any parameters specified as expressions:
898 
899  // calculate dependent (ie computed) params and check for errors:
900  processParams();
901 }
902 
903 //-----------------------------------------------------------------------------
904 // Function : Model::~Model
905 // Purpose : destructor
906 // Special Notes :
907 // Scope : public
908 // Creator : Christina Warrender, SNL,
909 // Creation Date : 10/12/11
910 //-----------------------------------------------------------------------------
912 {
913  std::vector<Instance*>::iterator iter;
914  std::vector<Instance*>::iterator first = instanceContainer.begin();
915  std::vector<Instance*>::iterator last = instanceContainer.end();
916 
917  for (iter=first; iter!=last; ++iter)
918  {
919  delete (*iter);
920  }
921 }
922 
923 //-----------------------------------------------------------------------------
924 // Function : Model::printOutInstances
925 // Purpose : debugging tool.
926 // Special Notes :
927 // Scope : public
928 // Creator : Christina Warrender, SNL,
929 // Creation Date : 10/12/11
930 //-----------------------------------------------------------------------------
931 std::ostream &Model::printOutInstances(std::ostream &os) const
932 {
933  std::vector<Instance*>::const_iterator iter;
934  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
935  std::vector<Instance*>::const_iterator last = instanceContainer.end();
936 
937  int i,isize;
938  isize = instanceContainer.size();
939  os << std::endl;
940  os << "Number of Synapse3 Instances: " << isize << std::endl;
941  os << " name model name Parameters" << std::endl;
942  for (i=0, iter=first; iter!=last; ++iter, ++i)
943  {
944  os << " " << i << ": " << (*iter)->getName() << "\t";
945  os << getName();
946  os << std::endl;
947  }
948 
949  os << std::endl;
950  return os;
951 }
952 
953 //-----------------------------------------------------------------------------
954 // Function : Model::forEachInstance
955 // Purpose :
956 // Special Notes :
957 // Scope : public
958 // Creator : David Baur
959 // Creation Date : 2/4/2014
960 //-----------------------------------------------------------------------------
961 /// Apply a device instance "op" to all instances associated with this
962 /// model
963 ///
964 /// @param[in] op Operator to apply to all instances.
965 ///
966 ///
967 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
968 {
969  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
970  op(*it);
971 }
972 
973 
974 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
975 {
976 
977  return new DeviceMaster<Traits>(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
978 }
979 
981 {
983  .registerDevice("synapse", 3)
984  .registerModelType("synapse", 3);
985 }
986 
987 } // namespace Synapse3
988 } // namespace Device
989 } // namespace Xyce