001    package cnslab.cnsnetwork;
002    
003    import java.util.*;
004    
005    import org.slf4j.Logger;
006    import org.slf4j.LoggerFactory;
007    
008    import cnslab.cnsmath.*;
009    import edu.jhu.mb.ernst.model.Synapse;
010    import edu.jhu.mb.ernst.util.slot.Slot;
011
012    /***********************************************************************
013    * Implementation of MN model,
014    * Same as VSICLIFNeuronV2, but no STDP is available.
015    * Please refer to VSICLIFNeuronV2 for details
016    * See Mihalas and Niebur 2009 paper
017    * 
018    * @version
019    *   $Date: 2012-08-04 13:43:22 -0500 (Sat, 04 Aug 2012) $
020    *   $Rev: 104 $
021    *   $Author: croft $
022    * @author
023    *   Yi Dong
024    * @author
025    *   David Wallace Croft, M.Sc.
026    * @author
027    *   Jeremy Cohen
028    ***********************************************************************/
029    public final class  VSICLIFNeuron
030      implements Neuron
031    ////////////////////////////////////////////////////////////////////////
032    ////////////////////////////////////////////////////////////////////////
033    {
034    
035    private static final Logger
036      LOGGER = LoggerFactory.getLogger ( VSICLIFNeuron.class );
037    
038    //
039
040    //  public Axon axon;
041    //  private double[] curr;//0 is exc current, 1 is inhib current
042    //  private double memV;
043    
044    private double timeOfNextFire;
045    
046    private double timeOfLastUpdate;
047    
048    private boolean record;
049
050    //  public static PrintStream p;
051    //  public static boolean print=false;
052
053    /** minimum rising time for neuron to fire */    
054    public static double MINRISETIME = 1e-4;
055    
056    /** time accuracy */
057    public static double tEPS = 1e-12;
058    
059    /** the criteria for removing synapses */
060    public static double rEPS = 1e-22;
061
062    public static double maxWeight=0;
063
064    public static double cost_Update = 10;
065    
066    public static double cost_Schedule = 1;
067    
068    public static double cost;
069
070    /** average time interval a neuron received spikes */
071    public double tAvg;
072    
073    /** last time the neuron received a spike */
074    public double lastInputTime;
075    
076    /** clamp the membrane voltage during absolute refractory period */
077    public double clamp_v;
078    
079    /** clamp the threshold during absolute refractory period */
080    public double clamp_t;
081    
082    /** judge whether the neuron fires or not */
083    public boolean fire;
084
085    public long tHost;
086    
087    public VSICLIFNeuronPara para;
088
089    /** linked list for state variables */
090    public TreeSet<State> state;
091    
092    /** pointer to the state variables */
093    public State[] sta_p;
094    
095    ////////////////////////////////////////////////////////////////////////
096    ////////////////////////////////////////////////////////////////////////
097    
098    public final class  State
099      implements Comparable<State>
100    ////////////////////////////////////////////////////////////////////////
101    ////////////////////////////////////////////////////////////////////////
102    {
103    
104    public double  time;
105    
106    public double  value;
107    
108    public byte    id;
109
110    ////////////////////////////////////////////////////////////////////////
111    ////////////////////////////////////////////////////////////////////////
112    
113    public  State (
114      final double  time,
115      final double  value,
116      final int     id )
117    ////////////////////////////////////////////////////////////////////////
118    {
119      this.time=time;
120      
121      this.value=value;
122      
123      this.id = ( byte ) id;
124    }
125    
126    ////////////////////////////////////////////////////////////////////////
127    ////////////////////////////////////////////////////////////////////////
128    
129    @Override
130    public int  compareTo ( final State  arg0 )
131    ////////////////////////////////////////////////////////////////////////
132    {
133      if ( para.allDecays[this.id] < para.allDecays[arg0.id])
134      {
135        return 1;
136      }
137      else if ( para.allDecays[this.id] > para.allDecays[arg0.id])
138      {
139        return -1;
140      }
141      else
142      {
143        if( this.id < arg0.id)
144        {
145          return -1;
146        }
147        else if ( this.id > arg0.id)
148        {
149          return 1;
150        }
151        else
152        {
153          return 0;
154        }
155      }
156    }
157
158    @Override
159    public String  toString ( )
160    ////////////////////////////////////////////////////////////////////////
161    {
162      String out;
163      
164      out = "time:" + time + " value:" + value + " id:" + id + " decay:"
165        + para.allDecays [ id ];
166      
167      return out;
168    }
169    
170    ////////////////////////////////////////////////////////////////////////
171    ////////////////////////////////////////////////////////////////////////
172    }
173
174    ////////////////////////////////////////////////////////////////////////
175    ////////////////////////////////////////////////////////////////////////
176    
177    public  VSICLIFNeuron ( final VSICLIFNeuronPara  para )
178    ////////////////////////////////////////////////////////////////////////
179    {
180      LOGGER.trace ( "constructor entered" );
181        
182      this.para = para;
183      
184      if ( maxWeight < para.CAP * ( para.THRESHOLD - para.VRESET )
185        / para.MINRISETIME )
186      {
187        maxWeight = para.CAP * ( para.THRESHOLD - para.VRESET )
188          / para.MINRISETIME;
189      }
190    }
191
192    ////////////////////////////////////////////////////////////////////////
193    // interface Neuron accessor methods
194    ////////////////////////////////////////////////////////////////////////
195
196    /*
197    public Axon getAxon()
198    {
199      return this.axon;
200    }
201    */
202
203    @Override
204    public double [ ]  getCurr ( final double  currTime )
205    ////////////////////////////////////////////////////////////////////////
206    {
207      final double [ ]  out = new double [ para.DECAY.length ];
208      
209      for(int a=0;a<para.DECAY.length;a++)
210      {
211        if(sta_p[a+2]==null)
212        {
213          out[a]=0;
214        }
215        else
216        {
217          out[a] = sta_p[a+2].value
218            * Math.exp ( -( currTime - sta_p[a+2].time ) *para.DECAY[a] )
219            * para.GLCAPDECAY[a] / (1 - para.ABDECAY[a]);
220        }
221      }
222      
223      return out;
224    }
225
226    @Override
227    public double  getMemV ( final double  currTime )
228    ////////////////////////////////////////////////////////////////////////
229    {
230      // if input comes inside the refractory period, memV not changed
231      if ( currTime < timeOfLastUpdate )
232      {       
233        return memVoltage ( timeOfLastUpdate );
234      }
235      else
236      {       
237        return memVoltage (currTime);
238      }
239    }
240
241    @Override
242    public boolean  getRecord ( )
243    ////////////////////////////////////////////////////////////////////////
244    {
245      return record;
246    }
247    
248    @Override
249    public long  getTHost ( )
250    ////////////////////////////////////////////////////////////////////////
251    {
252      return tHost;
253    }
254
255    @Override
256    public double  getTimeOfNextFire ( )
257    ////////////////////////////////////////////////////////////////////////
258    {
259      return timeOfNextFire;
260    }
261
262    @Override
263    public boolean  isSensory ( )
264    ////////////////////////////////////////////////////////////////////////
265    {
266      return false;
267    }
268
269    @Override
270    public boolean  realFire ( )
271    ////////////////////////////////////////////////////////////////////////
272    {
273      return fire;
274    }
275
276    ////////////////////////////////////////////////////////////////////////
277    // interface Neuron mutator methods
278    ////////////////////////////////////////////////////////////////////////
279
280    @Override
281    public void  setRecord ( final boolean  record )
282    ////////////////////////////////////////////////////////////////////////
283    {
284      this.record = record;
285    }
286    
287    @Override
288    public void  setTHost ( final long  id )
289    ////////////////////////////////////////////////////////////////////////
290    {
291      this.tHost = id;
292    }
293
294    @Override
295    public void  setTimeOfNextFire ( final double  timeOfNextFire )
296    ////////////////////////////////////////////////////////////////////////
297    {
298      this.timeOfNextFire = timeOfNextFire;
299    }
300
301    ////////////////////////////////////////////////////////////////////////
302    // interface Neuron lifecycle methods
303    ////////////////////////////////////////////////////////////////////////
304
305    @Override
306    public void  init (
307      final int      expid,
308      final int      trialid,
309      final Seed     idum,
310      final Network  net,
311      final int      id )
312    ////////////////////////////////////////////////////////////////////////
313    {
314      // initialization all the initial parameters.
315      
316      cost = Math.log ( cost_Schedule / cost_Update + 1.0 );
317      
318      this.tAvg = 0.005; // initial value is 5 ms
319      
320      this.lastInputTime = 0.0;
321      
322      this.timeOfLastUpdate = 0.0;
323      
324      this.timeOfNextFire = -1;
325      
326      final double
327        memV = para.ini_mem + para.ini_memVar * Cnsran.ran2 ( idum );
328      
329      final double  instantaneousThreshold = para.ini_threshold;
330
331      final double [ ]  curr = new double [ para.ini_curr.length ];
332      
333      for ( int  a = 0; a < curr.length; a++ )
334      {
335        curr [ a ] = para.ini_curr [ a ];
336      }
337
338      para.CON_v = para.IEXT / para.GL;
339      
340      para.CON = para.IEXT / para.GL - ( para.THRESHOLD - para.VREST
341        + para.A / para.B * para.IEXT / para.GL );
342
343      // state variables setup
344
345      // create linked table
346      
347      state = new TreeSet<State> ( );
348      
349      sta_p = new State [ para.DECAY.length + 2 ];
350      
351      // First state is Ng term
352      
353      sta_p [ 0 ] = new State ( 0, getNG ( memV, curr ), 0 );
354      
355      state.add ( sta_p [ 0 ] );
356      
357      sta_p[1] = new State(0,getNB(instantaneousThreshold,memV,curr),1);
358      
359      state.add(sta_p[1]);
360
361      for(int i=2; i< para.DECAY.length+2; i++)
362      {
363        sta_p[i] = new State(0,getCurr(i-2,curr),i);
364        
365        state.add(sta_p[i]);
366      }
367      
368      /*
369      //System.out.println("starting");
370      Iterator<State> iter= state.iterator();
371      while(iter.hasNext())
372      {
373        //System.out.println(iter.next());
374      }
375      //System.out.println("ending");
376      */
377
378      double dt,vc;
379      
380      double de = safeD(0.0) ;
381      
382      double nextTime = (-(memV-instantaneousThreshold)/de);
383      
384      dt=nextTime;
385      
386      //  if(nowV-nowT>0)return -1.0;
387      
388      while (de >0 && nextTime < 1.0 && !(dt>0?dt<tEPS:-dt<tEPS)) 
389      {
390        de = safeD(nextTime);
391        
392        vc = memStheta(nextTime);
393        
394        dt = (-vc/de);
395        
396        //System.out.print(
397        //  "n:"+nextTime+" s:"+(-vc)+"/"+de+"="+dt+" Etime:"
398        //  +(time+nextTime));
399        
400        nextTime += dt; 
401      }
402
403      if( de <0 || nextTime > 1.0)
404      {
405        fire = false;
406        nextTime = -1.0;
407      }
408      else if((dt>0?dt<tEPS:-dt<tEPS))
409      {
410        fire = true;
411      }
412      else
413      {
414        //System.out.println("error condition in init");
415      }
416
417      if(nextTime<0) //neuron will not fire at all
418      {
419
420      }
421      else
422      {
423        final Slot<FireEvent>  fireEventSlot = net.getFireEventSlot ( );
424        
425        // nextTime = (timeOfLastUpdate>0.0)
426        //   ?(timeOfLastUpdate-0.0-Math.log(nextTime)/para.K)
427        //   :(-1.0*Math.log(nextTime)/para.K);
428        
429        if(net.getClass().getName().equals("cnslab.cnsnetwork.ANetwork"))
430        {
431          fireEventSlot.offer (
432            new AFireEvent(
433              id,
434              nextTime,
435              net.info.idIndex,
436              ((ANetwork) net).aData.getId((ANetwork) net)));
437        }
438        else if ( net.getClass ( ).getName ( ).equals (
439          "cnslab.cnsnetwork.Network" ) )
440        {
441          fireEventSlot.offer ( new FireEvent(id, nextTime));
442        }
443        else
444        {
445          throw new RuntimeException("Other Network Class doesn't exist");
446        }
447        timeOfNextFire = nextTime;
448      }
449    }
450
451    @Override
452    public double  updateFire ( )
453    ////////////////////////////////////////////////////////////////////////
454    {
455      //    //System.out.println("fire at:"+timeOfNextFire);
456      
457      // update state variables containing membrane voltage and threshold
458      // because of the resetting.
459      
460      double baseline;
461      
462      double nowV, nowT;
463      
464      if(fire) // for real fire
465      {
466        // backup current threshold
467        final double backCT
468          = memVoltage(timeOfNextFire) - memStheta(timeOfNextFire);
469        
470        sta_p[0].value
471          *= Math.exp(-(timeOfNextFire-sta_p[0].time+para.ABSREF)
472            *para.allDecays[0]);
473        
474        sta_p[0].time = timeOfNextFire+para.ABSREF;
475        
476        sta_p[1].value
477          *= Math.exp(-(timeOfNextFire-sta_p[1].time+para.ABSREF)
478            *para.allDecays[1]);
479        
480        sta_p[1].time = timeOfNextFire+para.ABSREF;
481
482        //membrane voltage reset.
483        
484        //future memVoltage
485        
486        double cVoltage = memVoltage(timeOfNextFire+para.ABSREF);
487        
488        // change memStheta(timeOfNextFire) to 0 later on may be beneficial
489        
490        //    double cThreshold = cVoltage - memStheta(timeOfNextFire);
491        
492        // change memStheta(timeOfNextFire) to 0 later on may be beneficial
493        
494        // double cThreshold
495        //   = memVoltage(timeOfNextFire) - memStheta(timeOfNextFire);
496        
497        //System.out.println(
498        //"abT:"+backCT+" memV:"+memVoltage(timeOfNextFire));
499        
500        //System.out.println(
501        //  "abT2:"+(memVoltage(timeOfNextFire)
502        //  - memStheta(timeOfNextFire)));
503
504        //membrane voltage offset
505        
506        double vOffset = para.VRESET - cVoltage;
507        
508        //threshold in future;
509        
510        double cdiff = (cVoltage - memStheta(timeOfNextFire+para.ABSREF));
511        
512        //threshold offset
513        
514        final double  tOffset
515          = Math.max ( para.RRESET, backCT + para.THRESHOLDADD )
516          - cdiff;
517
518        sta_p[0].value += (1-para.ABGLCAP)*vOffset;
519        
520        sta_p[1].value += para.ABGLCAP*vOffset - tOffset; 
521
522        // System.out.println("after fire voltage:"
523        //   +memVoltage(timeOfNextFire+para.ABSREF)
524        //   +" v-t:"+memStheta(timeOfNextFire+para.ABSREF));
525        
526        //    if(clamp_v==Double.MAX_VALUE) //if clamp_v is not set;
527
528        clamp_v= para.VRESET;
529        
530        clamp_t= Math.max(para.RRESET,backCT+para.THRESHOLDADD);
531
532        // this section is for spike triggered current
533        
534        for(int a=0;a<para.DECAY.length;a++)
535        {
536          //update the currents if spike trigger current is non zero
537          
538          if( para.IRATIO[a]!=1.0 || para.IADD[a] !=0)
539          {
540            // System.out.println("added");
541            
542            //update current to fire time;
543            
544            if(sta_p[a+2]==null) //activate it
545            {
546              //System.out.println("act");
547              sta_p[a+2] = new State(timeOfNextFire+para.ABSREF,0,a+2);
548              state.add(sta_p[a+2]);
549            }
550            else
551            {
552              sta_p[a+2].value
553                *= Math.exp(-(timeOfNextFire-sta_p[a+2].time+para.ABSREF)
554                  *para.allDecays[a+2]);
555              
556              sta_p[a+2].time = timeOfNextFire+para.ABSREF;
557            }
558
559            // current at timeofnextfire
560            
561            double currNow = sta_p[a+2].value*para.GLCAPDECAY[a]
562              / (1 - para.ABDECAY[a]);
563            
564            double  currAfter = ( para.IRATIO [ a ] * currNow
565              * Math.exp ( para.ABSREF * para.allDecays [ a + 2 ] )
566                + para.IADD [ a ] )
567              * Math.exp ( -para.ABSREF * para.allDecays [ a + 2 ] );
568            
569            double  changeCurr = currAfter - currNow;
570            
571            // System.out.print (
572            //   "after:" + currAfter + " now:" + currNow + " " );
573
574            sta_p [ 0 ].value
575              += changeCurr / para.GLCAPDECAY [ a ] * ( para.ABGLCAP - 1 );
576            
577            sta_p [ 1 ].value -= changeCurr/para.BCAPDECAY[a]*para.ABGLCAP;
578            
579            sta_p [ a + 2 ].value
580              += ( changeCurr / para.GLCAPDECAY [ a ] )
581              * ( 1 - para.ABDECAY [ a ] );
582            
583            /*
584            sta_p[0].value
585              += input.weight/para.GLCAPDECAY[a]*(para.ABGLCAP-1);
586              
587            sta_p[1].value
588              -= input.weight/para.BCAPDECAY[a]*para.ABGLCAP;
589              
590            sta_p[a+2].value
591              += (changeCurr/para.GLCAPDECAY[a])*(1 - para.ABDECAY[a]);
592            */
593            //System.out.print(
594            //  " bycalcu:"+sta_p[a+2].value*para.GLCAPDECAY[a]
595            //  / (1 - para.ABDECAY[a])+" ");
596          }
597        }
598
599        // System.out.println ( "after fire curr:"
600        //   +getCurr(timeOfNextFire+para.ABSREF)[0]+" "
601        //   +getCurr(timeOfNextFire+para.ABSREF)[1]);
602
603        timeOfLastUpdate = timeOfNextFire+para.ABSREF;
604        
605        baseline  = timeOfNextFire+para.ABSREF;
606        
607        nowV = para.VRESET;
608        
609        nowT = Math.max(para.RRESET,backCT+para.THRESHOLDADD);
610      }
611      else
612      {
613        baseline = timeOfNextFire;
614        
615        nowV = memStheta(baseline);
616        
617        nowT = 0;
618      }
619
620      double dt,vc;
621      
622      double de = safeD(baseline);
623      
624      double nextTime = (-(nowV - nowT))/de;
625      
626      dt=nextTime;
627
628      while (de >0 && nextTime < cost*tAvg) 
629      {
630        de = safeD(baseline+nextTime);
631        
632        vc = memStheta(baseline+nextTime);
633        
634        dt = (-vc/de);
635        
636        if(dt>0?dt<tEPS:-dt<tEPS)
637        {
638          fire=true;
639          
640          //no spike within absolute refractory period.
641          
642          //if(nextTime < para.ABSREF) return -1.0;
643          
644          //System.out.println(
645          //  "Again:"+(nextTime+baseline - timeOfNextFire));
646          
647          return nextTime+baseline - timeOfNextFire;
648        }
649        
650        nextTime += dt; 
651      }
652
653      if ( de < 0 || nextTime > 1.0 )
654      {
655        fire = false;
656        
657        return -1.0;
658      }
659      else
660      {
661        fire = false;
662        
663        return nextTime+baseline - timeOfNextFire;
664      }
665    }
666
667    @Override
668    public double  updateInput (
669      final double   time,
670      final Synapse  input )
671    ////////////////////////////////////////////////////////////////////////
672    {
673      // System.out.println(
674      //   "get input at:"+time+ " syn:"+input+ " membrane voltage is:"
675      //   +memVoltage(time));
676      // System.out.println("beg: t:"+time+ " s:"+input+ " mV:"
677      //   + memVoltage(time) +" mtV:"+memStheta(time));
678
679      // update the tAvg;
680      
681      tAvg = tAvg * 0.8 + ( time - lastInputTime ) * 0.2;
682      
683      lastInputTime = time;
684      
685      // System.out.println("before updateInput:  memV: " + memV
686      //   + " instantThresh: " + instantaneousThreshold + " curr0: "
687      //   + curr[0] + " curr1: " + curr[1]);
688      // p.println("updateInput"+time);
689      // p.flush();
690      
691      /*
692       double [] oldcurr  = new double [curr.length];
693       oldcurr[0] = curr[0];
694       oldcurr[1] = curr[1];
695       double oldMem=memV ;
696       double VACC = 1E-9; // accuracy in voltage for spike to be generated
697       */
698      // System.out.println("0t:"+time+ " s:"+input+ " mV:"
699      //   + memVoltage(time) +" mtV:"+memStheta(time)+ " th:"
700      //   +(memVoltage(time)-memStheta(time)));
701
702      // update state 0,1 to current time;
703      
704      sta_p [ 0 ].value *= Math.exp (
705        -( time - sta_p [ 0 ].time ) * para.allDecays [ 0 ] );
706      
707      // System.out.println("ng decay:"+Math.exp(-(time-sta_p[0].time)
708      //   *para.allDecays[0]));
709
710      sta_p [ 0 ].time = time;
711      
712      sta_p [ 1 ].value *= Math.exp (
713        -( time - sta_p [ 1 ].time ) * para.allDecays [ 1 ] );
714      
715      sta_p [ 1 ].time = time;
716
717      // System.out.println("mid1: t:"+time+ " s:"+input+ " mV:"
718      //   + memVoltage(time) +" mtV:"+memStheta(time));
719
720      //check whether the input is deleted
721      
722      if ( sta_p [ input.getType ( ) + 2 ] == null ) //activate it
723      {
724        //System.out.println("act");
725        
726        sta_p [ input.getType ( ) + 2 ] = new State ( time, 0, input.getType ( ) + 2 );
727        
728        state.add ( sta_p [ input.getType ( ) + 2 ] );
729      }
730      else
731      {
732        sta_p [ input.getType ( ) + 2 ].value *= Math.exp (
733          -( time - sta_p [ input.getType ( ) + 2 ].time )
734          * para.allDecays [ input.getType ( ) + 2 ] );
735        
736        sta_p [ input.getType ( ) + 2 ].time = time;
737      }
738
739      // System.out.println("mid2: t:"+time+ " s:"+input+ " mV:"
740      //   + memVoltage(time) +" mtV:"+memStheta(time));
741
742      // add the extra state values (0,2,this synapse) by getting input
743      // spike.
744      
745      sta_p [ 0 ].value += input.getWeight ( )
746        / para.GLCAPDECAY [ input.getType ( ) ] * ( para.ABGLCAP - 1 );
747      
748      sta_p [ 1 ].value
749        -= input.getWeight ( ) / para.BCAPDECAY [ input.getType ( ) ] * para.ABGLCAP;
750      
751      sta_p [ input.getType ( ) + 2 ].value
752        += ( input.getWeight ( ) / para.GLCAPDECAY [ input.getType ( ) ] )
753        * ( 1 - para.ABDECAY [ input.getType ( ) ] );
754
755      double nextTime;
756      
757      double baseline;
758      
759      double nowV  = memVoltage ( time );
760      
761      double nowT =  nowV - memStheta ( time );
762      
763      if ( time < timeOfLastUpdate )
764      {
765        // set the offset of the membraneVoltage to make sure at the
766        // timeOfLastUpdate the membraneVoltage is not changed at all
767        // CON_v = CON_v - (memStheta(timeOfLastUpdate) - nowMem);
768        
769        /*
770        if(clamp_v==Double.MAX_VALUE) //if clamp_v is not set;
771        {
772          clamp_v= nowV;
773          clamp_t= nowT;
774        }
775        */
776        
777        final double  vFuture = memVoltage ( timeOfLastUpdate );
778        
779        final double  voltageOffset = ( vFuture - clamp_v );
780        
781        final double
782          tOffset = vFuture - memStheta ( timeOfLastUpdate ) - clamp_t;
783        
784        sta_p [ 0 ].value += -( 1 - para.ABGLCAP ) * voltageOffset
785          * Math.exp ( ( timeOfLastUpdate - time ) * para.allDecays [ 0 ] );
786        
787        sta_p [ 1 ].value += -( para.ABGLCAP * voltageOffset - tOffset )
788          * Math.exp ( ( timeOfLastUpdate - time ) * para.allDecays [ 1 ] );
789        
790        //System.out.println("nowV:"+nowV+" futV:"
791        //  +memVoltage(timeOfLastUpdate)+" clamp_v:"+clamp_v);
792        
793        //System.out.println("nowT:"+nowT+" futT:"
794        //  +(memVoltage(timeOfLastUpdate)-memStheta(timeOfLastUpdate))
795        //  +" clamp_6:"+clamp_t);
796        
797        //  sta_p[0].value += (1-para.ABGLCAP)*vOffset;
798        
799        //  sta_p[1].value += para.ABGLCAP*vOffset - tOffset;
800        
801        nowV = clamp_v;
802        
803        nowT = clamp_t;
804        
805        baseline = timeOfLastUpdate;
806      }
807      else
808      {
809        clamp_v = Double.MAX_VALUE;
810        
811        clamp_t = Double.MAX_VALUE;
812        
813        //if(input.to==1)
814        {
815          // System.out.println("t:"+time+ " s:"+input+ " mV:"
816          //   + memVoltage(time) +" mtV:"+memStheta(time)+ " th:"
817          //   +(memVoltage(time)-memStheta(time))+ " last:"
818          //   +timeOfLastUpdate);
819          //
820          // System.out.println("t:"+time+ " s:"+input+ " mV:"+memV
821          //   +" mtV:"+ (memV- instantaneousThreshold)+ " th:"
822          //   +instantaneousThreshold);
823          
824// TODO:  Is this for debugging only or does it have side-effects?          
825          final double [ ]  out = getCurr ( time );
826          
827          //System.out.println("c0:"+out[0]+ " c1:"+out[1]);
828        }
829        
830        timeOfLastUpdate=time;
831        
832        baseline = time;
833      }
834
835      double dt, vc;
836      
837      double  de = safeD ( baseline );
838      
839      nextTime = ( -( nowV - nowT ) / de );
840      
841      dt = nextTime;
842      
843      // if ( nowV - nowT > 0 ) return -1.0;
844      
845      if ( ( nowV - nowT ) < 0 )
846      {
847        
848        while ( de > 0 && nextTime < cost * tAvg ) 
849        {
850          de = safeD ( baseline + nextTime );
851          
852          vc = memStheta ( baseline + nextTime );
853          
854          dt = ( -vc / de );
855          
856          // System.out.print("n:"+nextTime+" s:"+(-vc)+"/"+de+"="+dt
857          //   +" Etime:"+(time+nextTime));
858          
859          if ( dt > 0 ? dt < tEPS : -dt < tEPS )
860          {
861            fire = true;
862            
863            // System.out.println();
864            
865            // if(nextTime < timeOfLastUpdate - time)
866            // {
867            //   //System.out.println("fail to fire nextTime:"+nextTime
868            //   // +" smaller than:"+(timeOfLastUpdate - time));
869            //   return -1.0; //no spike within absolute refractory period.
870            // }
871            
872            // System.out.println("N :"+input.to+" fire:"
873            //   +(time>timeOfLastUpdate?nextTime:nextTime
874            //   +timeOfLastUpdate-time)
875            //   + " memV:"+memStheta(baseline+nextTime));
876            
877            return ( time > timeOfLastUpdate
878              ? nextTime : nextTime + timeOfLastUpdate - time );
879          }
880
881          nextTime += dt; 
882        }
883      }
884      
885      if ( de < 0 || nextTime > 1.0 )
886      {
887        fire = false;
888        
889        return -1.0;
890      }
891      else
892      {
893        fire = false;
894        
895        return ( time > timeOfLastUpdate
896          ? nextTime : nextTime + timeOfLastUpdate - time );
897      }
898      
899      // System.out.println();
900      
901      // System.out.println("fail to fire dt:"+dt+ " nextTime:"+nextTime
902      //   + " test:"+memStheta(time+0.10316241162745285)+ " deri:"+de
903      //   + " safeD:"+safeD(time+0.10316241162745285));
904      //
905      // return -1.0;
906    }
907
908    ////////////////////////////////////////////////////////////////////////
909    // overridden Object methods
910    ////////////////////////////////////////////////////////////////////////
911
912    @Override
913    public String toString()
914    ////////////////////////////////////////////////////////////////////////
915    {
916      String tmp="";
917      //    tmp=tmp+"MemVol:"+memV+"\n";
918      tmp=tmp+"Current:"+"\n";
919      //    for(int i=0;i<curr.length;i++)
920      //    {
921      //      tmp=tmp+"       curr"+i+" "+curr[i]+"\n";
922      //    }
923      //    tmp=tmp+axon;
924      return tmp;
925    }
926
927    ////////////////////////////////////////////////////////////////////////
928    // non-interface accessor methods
929    ////////////////////////////////////////////////////////////////////////
930    
931    /***********************************************************************
932    * get the current which is the last updated current
933    ***********************************************************************/
934    public double [ ]  getCurr ( )
935    ////////////////////////////////////////////////////////////////////////
936    {
937      double [] out = new double[para.DECAY.length];
938      
939      for(int a=0;a<para.DECAY.length;a++)
940      {
941        if(sta_p[a+2]==null)
942        {
943          out[a]=0;
944        }
945        else
946        {
947          out[a] = sta_p[a+2].value*para.GLCAPDECAY[a]
948            / (1 - para.ABDECAY[a]);
949        }
950      }
951      
952      return out;
953    }
954
955    public double getCurr (
956      final int         a,
957      final double [ ]  curr )
958    ////////////////////////////////////////////////////////////////////////
959    {
960      // Nj terms
961      
962      return (curr[a]/para.GLCAPDECAY[a])*(1 - para.ABDECAY[a]);
963    }
964
965    /***********************************************************************
966    * return nb term
967    ***********************************************************************/
968    public double  getNB (
969      double  instantaneousThreshold,
970      double  memV,
971      double  curr[] )
972    ////////////////////////////////////////////////////////////////////////
973    {
974      double nbTerm=para.VREST-memV+para.IEXT/(para.B*para.CAP);
975      
976      for(int a=0;a<curr.length;a++)
977      {
978        nbTerm+=curr[a]/para.BCAPDECAY[a];//replace b*cap for para.GL
979      }
980      
981      nbTerm*=para.ABGLCAP;
982      
983      nbTerm+=instantaneousThreshold-para.THRESHOLD;
984      
985      return -nbTerm;
986    }
987
988    /***********************************************************************
989    * return ng term ( membrane voltage - ABGLCAP * membranevoltageNg )
990    ***********************************************************************/
991    public double  getNG (
992      final double      memV,
993      final double [ ]  curr ) 
994    ////////////////////////////////////////////////////////////////////////
995    {
996      double  ngTerm1 = memV - para.VREST - para.IEXT / para.GL;
997      
998      // LOGGER.debug ( "curr.length:  {}", curr.length );
999      
1000      for ( int  a = 0; a < curr.length; a++ )
1001      {
1002        ngTerm1 -= curr [ a ] / para.GLCAPDECAY [ a ];
1003      }
1004      
1005      return ngTerm1 - ngTerm1 * para.ABGLCAP;
1006    }
1007
1008    public double  getSensoryWeight ( )
1009    ////////////////////////////////////////////////////////////////////////
1010    {
1011      throw new RuntimeException (
1012        "This neuron type doesn't use the Sensory Weight Functions!" );
1013    }
1014
1015    public double  getTimeOfLastUpdate ( )
1016    ////////////////////////////////////////////////////////////////////////
1017    {
1018      return timeOfLastUpdate;
1019    }
1020
1021    ////////////////////////////////////////////////////////////////////////
1022    // non-interface mutator methods
1023    ////////////////////////////////////////////////////////////////////////
1024    
1025    public void  setMemV ( final double  memV )
1026    ////////////////////////////////////////////////////////////////////////
1027    {
1028// TODO:  Why is this method body empty?
1029      
1030      return;
1031    }
1032    
1033    public void  setTimeOfLastUpdate ( final double  timeOfLastUpdate )
1034    ////////////////////////////////////////////////////////////////////////
1035    {
1036      this.timeOfLastUpdate = timeOfLastUpdate;
1037    }
1038
1039    ////////////////////////////////////////////////////////////////////////
1040    ////////////////////////////////////////////////////////////////////////
1041    
1042    public double memStheta(double t) //absolute time t;
1043    ////////////////////////////////////////////////////////////////////////
1044    {
1045//      double V=0.0;
1046//      Iterator<State> iter = state.iterator();
1047//      while(iter.hasNext())
1048//      {
1049//        State tmpState = iter.next();
1050//        if(t-tmpState.time!=0)
1051//        {
1052//          V += Math.exp(-(t-tmpState.time)
1053//            *para.allDecays[(int)tmpState.id])*tmpState.value;
1054//        }
1055//        else
1056//        {
1057//          V += tmpState.value;
1058//        }
1059//      }
1060//      return V+para.CON;
1061      
1062      double V=0,constant=0.0;
1063      
1064      Iterator<State> iter = state.iterator();
1065      
1066      State first = iter.next();
1067      
1068      State second;
1069      
1070      double firstV,secondV;
1071
1072      if(Math.abs(first.value)<rEPS && (int)first.id>1) 
1073      {
1074        iter.remove(); //delete the synapse if it is small
1075        
1076        sta_p[(int)first.id]=null;
1077      }
1078      
1079      if(first.time == t) // ignore no time change term
1080      {
1081        constant += first.value;
1082        
1083        if(iter.hasNext())
1084        {
1085          first = iter.next();
1086        }
1087        else
1088        {
1089          return V+constant+para.CON;
1090        }
1091      }
1092
1093      firstV = first.value;
1094      
1095      V = firstV;
1096      
1097      while(iter.hasNext())
1098      {
1099        second = iter.next();
1100        
1101        if(Math.abs(second.value)<rEPS && (int)second.id>1)
1102        {
1103          iter.remove(); //delete the synapse if it is small
1104          
1105          sta_p[(int)second.id]=null;
1106        }
1107        
1108        secondV = 0.0;
1109        
1110        if(second.time == t) // ignore no time change term
1111        {
1112          constant += second.value;
1113          
1114          if(iter.hasNext())
1115          {
1116            second = iter.next();
1117          }
1118          else
1119          {
1120            break;
1121          }
1122        }
1123
1124        secondV = second.value;
1125        
1126        V = Math.exp(-((para.allDecays[(int)first.id]
1127          - para.allDecays[(int)second.id])*t
1128          - (para.allDecays[(int)first.id]*first.time
1129          - para.allDecays[(int)second.id]*second.time)))*V
1130          + secondV;
1131        
1132        first=second;
1133      }
1134
1135      V = Math.exp ( -(para.allDecays[(int)first.id]
1136        *t - para.allDecays[(int)first.id]*first.time))*V;
1137      
1138      ////System.out.println("V:"+(V+para.CON_v+para.VREST));
1139      
1140      return V+para.CON+constant;
1141    }
1142
1143    /** absolute time t */
1144    public double  memVoltage ( final double  t )
1145    ////////////////////////////////////////////////////////////////////////
1146    {
1147//      double V=0.0;
1148//      Iterator<State> iter = state.iterator();
1149//      while(iter.hasNext())
1150//      {
1151//        State tmpState = iter.next();
1152//        if((int)tmpState.id != 1 ) // nb term will be ignored.
1153//        {
1154//          if(t-tmpState.time!=0)
1155//          {
1156//            if((int)tmpState.id == 0 ) // ng term
1157//            {
1158//              V += Math.exp(-(t-tmpState.time)
1159//                *para.allDecays[(int)tmpState.id])
1160//                *tmpState.value/(1-para.ABGLCAP);
1161//              // System.out.print("ng:"+(tmpState.value/(1-para.ABGLCAP))
1162//              + " de:"+Math.exp(-(t-tmpState.time)
1163//                *para.allDecays[(int)tmpState.id]));
1164//            }
1165//            else  //current terms
1166//            {
1167//              V += Math.exp(-(t-tmpState.time)
1168//                *para.allDecays[(int)tmpState.id])
1169//                *tmpState.value/(1 - para.ABDECAY[(int)tmpState.id-2]);
1170//              // System.out.print(" c:"+(tmpState.id-2)+" "
1171//              +(tmpState.value/(1 - para.ABDECAY[(int)tmpState.id-2]))
1172//              + " de:"+Math.exp(-(t-tmpState.time)
1173//                *para.allDecays[(int)tmpState.id]));
1174//            }
1175//          }
1176//          else
1177//          {
1178//            if((int)tmpState.id == 0 ) // ng term
1179//            {
1180//              V += tmpState.value/(1-para.ABGLCAP);
1181//              // System.out.print(
1182//              //   " ng:"+(tmpState.value/(1-para.ABGLCAP))+ " de:0");
1183//            }
1184//            else  //current terms
1185//            {
1186//              V += tmpState.value/(1 - para.ABDECAY[(int)tmpState.id-2]);
1187//
1188//              // System.out.print(" c:"+(tmpState.id-2)+" "
1189//              // +(tmpState.value/(1 - para.ABDECAY[(int)tmpState.id-2]))
1190//              // +" de:0");
1191//            }
1192//          }
1193//        }
1194//      }
1195//    
1196      // System.out.print("V:"+V+" memV:"+(V+para.CON_v+para.VREST)+"\n");
1197      // System.out.println("V:"+V+" memV:"+(V+para.CON_v+para.VREST));
1198      // System.out.println((V+para.CON_v+para.VREST));
1199
1200      double V=0;
1201      
1202      double constant=0;
1203      
1204      Iterator<State> iter = state.iterator();
1205      
1206      State first = iter.next();
1207      
1208      State second;
1209      
1210      double firstV,secondV;
1211
1212      if(first.id ==1) //ignore nb term
1213      {
1214        if(iter.hasNext())
1215        {
1216          first = iter.next();
1217        }
1218        else
1219        {
1220          return V+constant+para.CON_v+para.VREST;
1221        }
1222      }
1223
1224      if(first.time == t) // ignore no time change term
1225      {
1226        if(first.id ==0)
1227        {
1228          constant += first.value/(1-para.ABGLCAP);
1229        }
1230        else
1231        {
1232          constant += first.value/(1 - para.ABDECAY[(int)first.id-2]);
1233        }
1234        if(iter.hasNext())
1235        {
1236          first = iter.next();
1237        }
1238        else
1239        {
1240          return V+constant+para.CON_v+para.VREST;
1241        }
1242      }
1243
1244      if(first.id ==1) //ignore nb term
1245      {
1246        if(iter.hasNext())
1247        {
1248          first = iter.next();
1249        }
1250        else
1251        {
1252          return V+constant+para.CON_v+para.VREST;
1253        }
1254      }
1255
1256      if(first.id ==0)
1257      {
1258        firstV = first.value/(1-para.ABGLCAP);
1259      }
1260      else
1261      {
1262        //System.out.println(first.id);
1263        firstV = first.value/(1 - para.ABDECAY[(int)first.id-2]);
1264      }
1265
1266      V = firstV;
1267      while(iter.hasNext())
1268      {
1269        second = iter.next();
1270        secondV=0.0;
1271
1272        if( second.time == t && second.id != 1)
1273        {
1274          if(second.id ==0)
1275          {
1276            constant += second.value/(1-para.ABGLCAP);
1277          }
1278          else
1279          {
1280            constant += second.value/(1 - para.ABDECAY[(int)second.id-2]);
1281          }
1282          if(iter.hasNext())
1283          {
1284            second = iter.next();
1285          }
1286          else
1287          {
1288            break;
1289          }
1290        }
1291
1292
1293        if(second.id == 1)
1294        {
1295          if(iter.hasNext())
1296          {
1297            second = iter.next();
1298          }
1299          else
1300          {
1301            break;
1302          }
1303
1304        }
1305
1306
1307        if(second.id ==0)
1308        {
1309          secondV = second.value/(1-para.ABGLCAP);
1310        }
1311        else
1312        {
1313          secondV = second.value/(1 - para.ABDECAY[(int)second.id-2]);
1314        }
1315
1316        V = Math.exp(-((para.allDecays[(int)first.id]
1317          - para.allDecays[(int)second.id])*t
1318          - (para.allDecays[(int)first.id]*first.time
1319          -  para.allDecays[(int)second.id]*second.time)))*V
1320          + secondV;
1321        
1322        first=second;
1323      }
1324
1325      V = Math.exp ( -(para.allDecays[(int)first.id]*t
1326        - para.allDecays[(int)first.id]*first.time))*V;
1327      
1328      //System.out.println("V:"+(V+para.CON_v+para.VREST));
1329      
1330      return V+para.CON_v+para.VREST+constant;
1331    }
1332
1333    /** absolute time t */
1334    public double  safeD ( final double  t )
1335    ////////////////////////////////////////////////////////////////////////
1336    {
1337      // the smallest inverse decay of all negative state variables
1338      
1339      double tauSafe=Double.MAX_VALUE;
1340      
1341      //find the tauSafe
1342      
1343      Iterator<State> iter = state.descendingIterator();
1344      
1345      while(iter.hasNext())
1346      {
1347        State tmpState = iter.next();
1348        
1349        // System.out.println("value:"+tmpState.value+" delay:"
1350        //   + para.allDecays[(int)tmpState.id]
1351        //   + " id:"+(int)tmpState.id+ " time:"+tmpState.time);
1352        
1353        if(tmpState.value<0)
1354        {
1355          tauSafe = para.allDecays[(int)tmpState.id];
1356          
1357          break;
1358        }
1359      }
1360      
1361      ////System.out.println("
1362      //    //System.out.println("safe:"+tauSafe);
1363      //calculate the dV
1364      //
1365      
1366      double constant=0;
1367      
1368      double V=0;
1369      
1370      iter = state.iterator();
1371      
1372      State first = iter.next();
1373      
1374      State second;
1375      
1376      double firstV,secondV;
1377
1378      if(first.time == t) // ignore no time change term
1379      {
1380        if(first.value>0)
1381        {
1382          double maxDecay = Math.min(para.allDecays[(int)first.id],tauSafe);
1383          
1384          constant += -first.value*maxDecay;
1385        }
1386        else
1387        {
1388          constant += -first.value*para.allDecays[(int)first.id];
1389        }
1390
1391        if(iter.hasNext())
1392        {
1393          first = iter.next();
1394        }
1395        else
1396        {
1397          return V+constant;
1398        }
1399      }
1400
1401      if(first.value>0)
1402      {
1403        double maxDecay = Math.min(para.allDecays[(int)first.id],tauSafe);
1404        
1405        firstV = -first.value*maxDecay;
1406      }
1407      else
1408      {
1409        firstV = -first.value*para.allDecays[(int)first.id];
1410      }
1411
1412      V = firstV;
1413      
1414      while(iter.hasNext())
1415      {
1416        second = iter.next();
1417        
1418        secondV = 0.0;
1419
1420        if( second.time == t)
1421        {
1422          if(second.value>0)
1423          {
1424            double maxDecay
1425              = Math.min(para.allDecays[(int)second.id],tauSafe);
1426            
1427            constant += -second.value*maxDecay;
1428          }
1429          else
1430          {
1431            constant += -second.value*para.allDecays[(int)second.id];
1432          }
1433
1434          if(iter.hasNext())
1435          {
1436            second = iter.next();
1437          }
1438          else
1439          {
1440            break;
1441          }
1442        }
1443
1444        if(second.value>0)
1445        {
1446          double maxDecay
1447            = Math.min(para.allDecays[(int)second.id],tauSafe);
1448          
1449          secondV = -second.value*maxDecay;
1450        }
1451        else
1452        {
1453          secondV = -second.value*para.allDecays[(int)second.id];
1454        }
1455
1456        V = Math.exp(-((para.allDecays[(int)first.id]
1457          - para.allDecays[(int)second.id])*t
1458          - (para.allDecays[(int)first.id]*first.time
1459          -  para.allDecays[(int)second.id]*second.time)))*V+secondV;
1460        
1461        first=second;
1462      }
1463
1464      V = Math.exp( -(para.allDecays[(int)first.id]*t
1465        - para.allDecays[(int)first.id]*first.time))*V;
1466      
1467//      double dV=0;
1468//      iter = state.iterator();
1469//      while(iter.hasNext())
1470//      {
1471//        State tmpState = iter.next();
1472//        if(tmpState.value>0)
1473//        {
1474//          double maxDecay
1475//            = Math.min(para.allDecays[(int)tmpState.id],tauSafe);
1476//          if(t-tmpState.time!=0)
1477//          {
1478//            // dV -= Math.exp(-(t-tmpState.time)*maxDecay)
1479//            //   *tmpState.value*maxDecay;
1480//            dV -= Math.exp(-(t-tmpState.time)
1481//              *para.allDecays[(int)tmpState.id])*tmpState.value*maxDecay;
1482//          }
1483//          else
1484//          {
1485//            dV -= tmpState.value*maxDecay;
1486//          }
1487//        }
1488//        else
1489//        {
1490//          if(t-tmpState.time!=0)
1491//          {
1492//            dV -= Math.exp(-(t-tmpState.time)*para.allDecays[
1493//             (int)tmpState.id])*tmpState.value
1494//             *para.allDecays[(int)tmpState.id];
1495//          }
1496//          else
1497//          {
1498//            dV -= tmpState.value*para.allDecays[(int)tmpState.id];
1499//          }
1500//        }
1501//      }
1502      
1503      return V + constant;
1504    }
1505
1506    ////////////////////////////////////////////////////////////////////////
1507    ////////////////////////////////////////////////////////////////////////
1508    }