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