001    package cnslab.cnsnetwork;
002
003    import java.io.*;
004    import java.util.*;
005
006    import org.slf4j.Logger;
007    import org.slf4j.LoggerFactory;
008
009    import jpvm.jpvmException;
010    import jpvm.jpvmTaskId;
011
012    import cnslab.cnsmath.*;
013    import edu.jhu.mb.ernst.engine.DiscreteEvent;
014    import edu.jhu.mb.ernst.engine.DiscreteEventQueue;
015    import edu.jhu.mb.ernst.model.ModelFactory;
016    import edu.jhu.mb.ernst.model.ModulatedSynapse;
017    import edu.jhu.mb.ernst.model.Synapse;
018import edu.jhu.mb.ernst.util.seq.Seq;
019    import edu.jhu.mb.ernst.util.slot.ErnstQueueSlot;
020import edu.jhu.mb.ernst.util.slot.Slot;
021
022    /***********************************************************************
023    * Network structure to organize all the small pieces (neurons, layers,
024    * axons, recorders, etc.) together.
025    * 
026    * @version
027    *   $Date: 2012-08-04 13:43:22 -0500 (Sat, 04 Aug 2012) $
028    *   $Rev: 104 $
029    *   $Author: croft $
030    * @author
031    *   Yi Dong
032    * @author
033    *   David Wallace Croft
034    ***********************************************************************/
035    public class  Network
036    ////////////////////////////////////////////////////////////////////////
037    ////////////////////////////////////////////////////////////////////////
038    {
039      
040    private static final Class<Network>
041      CLASS = Network.class;
042  
043    private static final Logger
044      LOGGER = LoggerFactory.getLogger ( CLASS );
045    
046    //
047    
048    public int
049      countTrial,
050      expIdBack,
051      trialIdBack;
052
053    public Experiment  experiment;
054
055    /** Keep track of current simulated subExp id */
056    public int  subExpId;
057
058    /** Keep track of current Trials. */
059    public int trialId;
060
061    /** Size of Xedge */
062    public int xEdge;
063
064    /** Size of Yedge */
065    public int yEdge;
066
067    /** a data structure map "pre,x,y,suf" to neuron index */
068    public Map<String, Integer>  cellmap;
069
070    /** the seed value for this network */
071    public Seed  seed;
072
073    /** the system background firing rates */
074    public SimulatorParser  simulatorParser;
075
076    /** the minimum synaptic delay */
077    public double  minSynapticDelay;
078
079    /** for the output of the slave hosts */
080    public PrintStream  p;
081
082    /** the parallel machine informations */
083    public JpvmInfo  info;
084
085    /** used by the root host to monitor other host's time */
086    public double [ ]  localTime;
087
088    /** spike buffer to store the neuron spikes which needs to be sented */
089    public SpikeBuffer [ ]  spikeBuffers;
090
091    /** used for keep record of received spikes */
092    public int [ ]  received;
093    
094    /** recorded intracellular info */
095    public IntraRecBuffer  intraRecBuffers;
096
097    /** recorded info buffer */
098    public RecordBuffer  recordBuff;
099
100    /** neuron index base, the real index is index+base */
101    public int  base;
102
103    /** the root broadcasting time */
104    public double  rootTime; 
105
106    /** the end of Trial time */
107    public double  endOfTrial;
108
109    /** An array of neurons used in current Nethosts */
110    public Neuron [ ]  neurons;
111
112    /** A data structure mapping neuron id to the neuron's Axon. */
113    public Map<Integer, Axon>  axons;
114
115    /** Store the recorded data. */
116    public RecorderData  recorderData;
117
118    /** flag for the computation and communication threads to stop */
119    public boolean  stop;
120
121    /** Flag to indicate whether the trial is done or not */
122    public boolean  trialDone;
123
124    /** trial start flag */
125    public boolean  startSig;
126
127    /** flag for trial end */
128    public boolean  spikeState = true;
129    
130    // protected final instance variables
131    
132    protected final ModelFactory  modelFactory;
133    
134    protected final DiscreteEventQueue  discreteEventQueue;
135    
136    // protected non-final instance variables
137
138    /** The neuron fire queue */
139    protected Queue<FireEvent>  fireQueue;
140
141    /** The (internal) input spike queue */
142    protected Queue<InputEvent>  inputQueue;
143
144    /** The (external) input queue */
145    // used for poisson background firing event queue
146    protected Queue<PInputEvent>  poissonQueue;
147    
148    // private instance variables
149    
150    private final Seq<ModulatedSynapse>  modulatedSynapseSeq;
151    
152    //
153    
154    private Slot<FireEvent>    fireEventSlot;
155    
156    private Slot<InputEvent>   inputEventSlot;
157    
158    private Slot<PInputEvent>  pInputEventSlot;
159    
160    ////////////////////////////////////////////////////////////////////////
161    // constructor methods
162    ////////////////////////////////////////////////////////////////////////
163      
164    public  Network (
165      final ModelFactory           modelFactory,
166      final DiscreteEventQueue     discreteEventQueue,
167      final Seq<ModulatedSynapse>  modulatedSynapseSeq,
168      final Neuron [ ]             neurons,
169      final Map<Integer, Axon>     axons,
170      final double                 minSynapticDelay,
171      final SimulatorParser        simulatorParser,
172      final Seed                   seed )
173    ////////////////////////////////////////////////////////////////////////
174    {
175      this.modelFactory = modelFactory;
176      
177      this.discreteEventQueue = discreteEventQueue;
178      
179      this.modulatedSynapseSeq = modulatedSynapseSeq;
180      
181      this.neurons = neurons;
182      
183      this.axons = axons;
184      
185      this.minSynapticDelay = minSynapticDelay;
186      
187      this.simulatorParser = simulatorParser;
188      
189      this.seed = seed;
190      
191      this.recorderData = new RecorderData ( );
192    }
193
194    public  Network (
195      final ModelFactory           modelFactory,
196      final DiscreteEventQueue     discreteEventQueue,
197      final Seq<ModulatedSynapse>  modulatedSynapseSeq,
198      final Neuron [ ]             neurons,
199      final Map<Integer, Axon>     axons,
200      final JpvmInfo               info,
201      final int                    base,
202      final double                 minSynapticDelay,
203      final SimulatorParser        simulatorParser,
204      final Seed                   seed,
205      final Experiment             experiment )
206    ////////////////////////////////////////////////////////////////////////
207    {
208      this.modelFactory = modelFactory;
209      
210      this.discreteEventQueue = discreteEventQueue;
211      
212      this.modulatedSynapseSeq = modulatedSynapseSeq;
213      
214      this.neurons = neurons;
215      
216      this.axons = axons;
217      
218      this.info = info;
219      
220      this.base = base;
221      
222      this.minSynapticDelay = minSynapticDelay;
223      
224      this.simulatorParser = simulatorParser;
225      
226      this.seed = seed;
227      
228      this.experiment = experiment;
229      
230      this.recorderData = new RecorderData ( );
231    }
232
233    public  Network (
234      final ModelFactory           modelFactory,
235      final DiscreteEventQueue     discreteEventQueue,
236      final Seq<ModulatedSynapse>  modulatedSynapseSeq,
237      final Experiment             experiment,
238      final JpvmInfo               info,
239      final int                    base,
240      final double                 minSynapticDelay,
241      final SimulatorParser        simulatorParser,
242      final Seed                   seed )
243    ////////////////////////////////////////////////////////////////////////
244    {
245      this.modelFactory = modelFactory;
246      
247      this.discreteEventQueue = discreteEventQueue;
248      
249      this.modulatedSynapseSeq = modulatedSynapseSeq;
250      
251      this.experiment = experiment;
252      
253      this.info = info;
254      
255      this.base = base;
256      
257      this.minSynapticDelay = minSynapticDelay;
258      
259      this.simulatorParser = simulatorParser;
260      
261      this.seed = seed;
262      
263      this.recorderData = new RecorderData ( );
264    }
265
266    ////////////////////////////////////////////////////////////////////////
267    // accessor methods
268    ////////////////////////////////////////////////////////////////////////
269    
270    public DiscreteEventQueue  getDiscreteEventQueue ( )
271    ////////////////////////////////////////////////////////////////////////
272    {
273      return discreteEventQueue;
274    }
275    
276    public synchronized double  getLocalTime ( final int  i )
277    ////////////////////////////////////////////////////////////////////////
278    {
279      return localTime [ i ];
280    }
281    
282    public Slot<FireEvent>  getFireEventSlot ( )
283    ////////////////////////////////////////////////////////////////////////
284    {
285      return fireEventSlot;
286    }
287    
288    public FireEvent  getFirstFireEvent ( )
289    ////////////////////////////////////////////////////////////////////////
290    {
291      return fireQueue.firstItem ( );
292    }
293
294    public InputEvent  getFirstInputEvent ( )
295    ////////////////////////////////////////////////////////////////////////
296    {
297      return inputQueue.firstItem ( );
298    }
299
300    public PInputEvent  getFirstPInputEvent ( )
301    ////////////////////////////////////////////////////////////////////////
302    {
303      return poissonQueue.firstItem ( );
304    }
305
306    public Slot<InputEvent>  getInputEventSlot ( )
307    ////////////////////////////////////////////////////////////////////////
308    {
309      return inputEventSlot;
310    }
311    
312    public Slot<PInputEvent>  getPInputEventSlot ( )
313    ////////////////////////////////////////////////////////////////////////
314    {
315      return pInputEventSlot;
316    }
317    
318    ////////////////////////////////////////////////////////////////////////
319    // mutator methods
320    ////////////////////////////////////////////////////////////////////////
321    
322    public void  clearQueues ( )
323    ////////////////////////////////////////////////////////////////////////
324    {
325      fireQueue   .clear ( );
326    
327      inputQueue  .clear ( );
328    
329      poissonQueue.clear ( );
330      
331      discreteEventQueue.clear ( );
332    }    
333    
334    /***********************************************************************
335    * set a new value to localTime
336    * 
337    * @param localTime
338    *   the new value to be used
339    ***********************************************************************/
340    public synchronized void  setLocalTime (
341      final double  localTime,
342      final int     i )
343    ////////////////////////////////////////////////////////////////////////
344    {
345      this.localTime [ i ] = localTime;
346    }
347
348    ////////////////////////////////////////////////////////////////////////
349    ////////////////////////////////////////////////////////////////////////
350    
351    /***********************************************************************
352    * stop the testRun(); 
353    ***********************************************************************/
354    public void  stopRun ( )
355    ////////////////////////////////////////////////////////////////////////
356    {
357      stop = true;
358    }
359
360    /***********************************************************************
361    * Initializes the Network.
362    * fill up the first item for inputQueue, fireQueue, poissonQueue
363    * (the implementation of the queue is changed here),
364    * Initialized SyncNeuron (Index is the number of neurons).
365    ***********************************************************************/
366    public void  initNet ( )
367    ////////////////////////////////////////////////////////////////////////
368    {
369      //    subExpId=0; //the first subExp
370      //    trialId=-1; // the first trial;
371
372      // double tmp_time;
373      
374      //    minDelay = 0.001; //minimum delay is 1ms
375      //    inputQueue = new PriQueue<InputEvent>(); // assign the queue
376      //  inputQueue = new FiboQueue<InputEvent>(); // assign the queue
377      //    inputQueue = new TreeQueue<InputEvent>(); // assign the queue
378      
379      // assign the queue
380      
381      inputQueue = new MTreeQueue<InputEvent> ( );
382      
383      inputEventSlot = new ErnstQueueSlot<InputEvent> ( inputQueue );
384
385      //    fireQueue = new TreeQueue<FireEvent>();
386      
387      fireQueue = new MTreeQueue<FireEvent> ( );
388      
389      fireEventSlot = new ErnstQueueSlot<FireEvent> ( fireQueue );
390
391      // if(bFreq>0.0)
392      // {
393      
394      // assign the queue
395      
396      poissonQueue = new MTreeQueue<PInputEvent> ( );
397      
398      pInputEventSlot = new ErnstQueueSlot<PInputEvent> ( poissonQueue );
399      
400      // }
401
402      stop = false;
403      
404      if (  info != null )
405      {
406        spikeBuffers = new SpikeBuffer [ info.numTasks ];
407        
408        // adding the clock neuron at the end of neuron list
409        
410        neurons [ neurons.length - 1 ] = new SYNNeuron ( this );
411        
412        for ( int i = 0; i < info.numTasks; i++ )
413        {
414          spikeBuffers [ i ] = new SpikeBuffer ( );
415        }
416
417        recordBuff = new RecordBuffer ( );
418
419        received = new int [ info.numTasks ];
420        
421        for ( int  iter = 0; iter < info.numTasks; iter++ )
422        {
423          // leave mark here
424          
425          received [ iter ] = 1;
426        }
427
428        intraRecBuffers
429          = new IntraRecBuffer ( experiment.recorder.intraNeurons ( ) );
430
431        // send initial input spikes from the sensory neuron to all the
432        // neurons in the network
433        
434        /*
435         for(int i= 1; i< neurons.length; i++)
436         {
437         // 5Hz background input
438         tmp_time=-Math.log(Cnsran.ran2(idum))/5.0;
439         // sensory neuron send spikes to the other neurons
440         inputQueue.insertItem( new InputEvent(0,tmp_time,i,1e-10));
441         }
442         inputQueue.show();
443         */
444        /*
445         if(bFreq>0.0)
446         {
447      // poissonQueue = new PriQueue<PInputEvent>(); // assign the queue
448      poissonQueue = new MTreeQueue<PInputEvent>(); // assign the queue
449      //    poissonQueue = new TreeQueue<PInputEvent>(); // assign the queue
450      for(int i=0; i<neurons.length; i++)
451      {
452        if(!neurons[i].isSensory())
453        {
454          poissonQueue.insertItem (
455            new PInputEvent (
456              -Math.log ( Cnsran.ran2 ( idum ) ) / bFreq,
457              new Synapse ( base+i, 1e-10, 0 ),
458              0 ) );
459        }
460      }
461         }
462         */
463        /*
464
465         for(int i=0; i<neurons.length; i++)
466         {
467         if(neurons[i].isSensory())
468         {
469         // sensory neuron send spikes to the other neurons
470         fireQueue.insertItem( new FireEvent(i+base,0.0));
471         }
472         }
473         */
474
475        try
476        {
477          
478          final jpvmTaskId parentJpvmTaskId = info.parentJpvmTaskId;
479          
480          final String
481            host = parentJpvmTaskId == null
482            ? "null-task-id" : parentJpvmTaskId.getHost ( ); 
483            
484          final FileOutputStream  out = new FileOutputStream (
485            "log/"
486            + host
487            + "_myfile"
488            + info.idIndex
489            + ".txt" );
490          
491          p = new PrintStream ( out );
492          
493          // p.println(base+neurons[neurons.length-1].toString());
494          
495          p.println ( "Logfile start" );
496        }
497        catch ( final Exception  e )
498        {
499          e.printStackTrace ( );
500          
501          LOGGER.error ( e.getMessage ( ), e );
502        }
503
504        final String  curDir = System.getProperty ( "user.dir" );
505        
506        p.println ( curDir );
507        
508        //added
509        /*
510        for(int iter=0;iter<info.numTasks;iter++)
511        {       
512          while(!received[iter].empty())
513          {
514            received[iter].pop();
515          }
516          received[iter].push(new Object());
517        }
518        */        
519        //added over
520      }
521      
522      // init();
523    }
524
525    /***********************************************************************
526    * Initialize the queues, put the first element into each of the queues.
527    * 
528    * Called from PRun.run(). 
529    ***********************************************************************/
530    public void  init ( )
531    ////////////////////////////////////////////////////////////////////////
532    {
533      // I added this as I was worried that the queues were not being
534      // cleared between repetitions of subexperiments.
535      
536      // But then again, maybe there are special elements that need to
537      // stay in there for distributed computing.  I need to look into the
538      // differences between init() and initNet() and when they are called.
539      
540      // clearQueues ( );
541      
542      discreteEventQueue.clear ( );
543      
544      final SubExp  subExp = experiment.subExp [ subExpId ];
545      
546      final Collection<DiscreteEvent>
547        discreteEventCollection = subExp.getDiscreteEventCollection ( );
548      
549      if ( discreteEventCollection != null )
550      {
551        discreteEventQueue.addAll ( discreteEventCollection );
552      }
553      
554      clearModulationFactors ( );      
555      
556      // double tmp_time;
557      
558      // minimum delay is 1ms      
559      // minDelay = 0.001;
560      
561      stop = false;
562
563      // trialDone=false;
564
565      spikeState = true;
566
567      /* this modification make old simulator done's run any more
568
569      trialId++;
570      if(trialId == exp.subExp[subExpId].repetition)
571      {       
572        trialId =0;
573        subExpId++;
574      }
575      */
576      
577      // p.println("sub "+subExpId+ "tri: "+trialId);
578
579      // only initialize when subExp is within the range
580      
581      if ( subExpId < experiment.subExp.length )
582      {
583        /*
584        for(int iter=0;iter<info.numTasks;iter++)
585        {       
586          while(!received[iter].empty())
587          {
588            received[iter].pop();
589          }
590          
591          received[iter].push(new Object());
592        }
593        */
594
595        if ( info != null )
596        {
597          for ( int  i = 0; i < info.numTasks; i++ )
598          {
599            spikeBuffers [ i ].buff.clear ( );
600          }
601        }
602
603        // recordBuff.buff.clear();
604        
605        // clear intracellular info
606
607        // intraBuff.init();
608
609        if ( simulatorParser.backgroundFrequency > 0.0 )
610        {
611          for ( int  i = 0; i < neurons.length; i++ )
612          {
613            if ( !neurons [ i ].isSensory ( ) )
614            {
615              final double  inputEventTime
616                = -Math.log ( Cnsran.ran2 ( seed ) )
617                  / simulatorParser.backgroundFrequency;
618              
619              final Synapse  synapse = modelFactory.createSynapse (
620                base + i,
621                ( byte ) simulatorParser.bChannel,
622                ( float ) simulatorParser.backgroundStrength );
623              
624              final PInputEvent  pInputEvent = new PInputEvent (
625                inputEventTime,
626                synapse,
627                -1 ); // sourceId
628                 
629              poissonQueue.insertItem ( pInputEvent );
630            }
631          }
632        }
633
634        // put the other sources of inputs
635        
636        final Stimulus [ ]  stimuli = subExp.stimuli;
637        
638        final int  stimulusCount = stimuli.length;
639        
640        for ( int  i = 0; i < stimulusCount; i++ )
641        {
642          final Stimulus  stimulus = stimuli [ i ];
643          
644          // unify the seed
645          
646          stimulus.seed = seed;
647          
648          final ArrayList<PInputEvent>
649            pInputEventArrayList = stimulus.init ( i );
650          
651          for ( final PInputEvent  pInputEvent : pInputEventArrayList )
652          {
653            poissonQueue.insertItem ( pInputEvent );
654          }
655        }
656        
657        final int
658          neuronsLengthMinusOne = neurons.length - 1;
659
660        for ( int  i = 0; i < neuronsLengthMinusOne; i++ )
661        {
662          // all neurons will be initialized
663          
664          final Neuron  neuron = neurons [ i ];
665          
666          neuron.init (
667            subExpId,
668            trialId,
669            seed,
670            this,
671            base + i );
672
673          // if(neurons[i].isSensory())
674          // {
675          //   // sensory neuron send spikes to the other neurons
676          //
677          //   fireQueue.insertItem (
678          //     new FireEvent ( i + base, 0.0 ) );
679          //
680          //   // sensory neuron send spikes to the other neurons
681          //
682          //   fireQueue.insertItem (
683          //     new FireEvent ( i + base, neurons [ i ].updateFire ( ) ) );
684          // }
685          // else
686          // {
687          // }
688        }
689        
690        // p.println("neurons number: "+neurons.length);
691        
692        if ( info != null )
693        {
694          if ( info.numTasks == 1
695            && experiment.recorder.intraEle.size ( ) == 0 )
696          {
697            // sensory neuron send spikes to the other neurons
698            
699            fireQueue.insertItem (
700              new FireEvent (
701                neurons.length - 1 + base,
702                experiment.subExp [ subExpId ].trialLength ) );
703          }
704          else
705          {
706            // sensory neuron send spikes to the other neurons
707            
708            fireQueue.insertItem (
709              new FireEvent (
710                neurons.length - 1 + base,
711                0.0 ) );
712          }
713        }
714      }
715    }
716
717    /***********************************************************************
718    * One time initialization, initialize the structure to store the times.
719    ***********************************************************************/
720    public void  initMain ( )
721    ////////////////////////////////////////////////////////////////////////
722    {
723      // double tmp_time;
724      
725      // minimum delay is 1ms
726      
727      // minDelay = 0.001;
728      
729      // fireQueue = new TreeQueue<FireEvent>();
730      
731      stop = false;
732      
733      if ( info != null )
734      {
735        localTime = new double [ info.numTasks ];
736      }
737      
738      // send initial input spikes from the sensory neuron to all the
739      // neurons in the network
740      
741      /*
742       for(int i= 1; i< neurons.length; i++)
743       {
744       // 5Hz background input       
745       tmp_time=-Math.log(Cnsran.ran2(idum))/5.0;
746       //sensory neuron send spikes to the other neurons
747       inputQueue.insertItem( new InputEvent(0,tmp_time,i,1e-10));
748       }
749       inputQueue.show();
750       */
751      /*
752       tmp_time = (-Math.log(Cnsran.ran2(idum))/freq);
753       for(int i=0; i<info.endIndex.length; i++)
754       {
755       if(! (neurons[info.endIndex[i]] instanceof BKPoissonNeuron))
756       {
757       //sensory neuron send spikes to the other neurons       
758       fireQueue.insertItem( new FireEvent(info.endIndex[i]+base,tmp_time));
759       }
760       }
761       */
762    }
763
764    /***********************************************************************
765    * process the event from fireQueue 
766    * 
767    * @param
768    *   firstFire 
769    ***********************************************************************/
770    /*
771    public void fireProcess(FireEvent firstFire)
772    ////////////////////////////////////////////////////////////////////////
773    {
774    double tmp_firetime;
775    //note the sensory neuron will never fire
776    //p.println("fire: "+firstFire);
777    //if(firstFire.index!=0)inputQueue.show();
778    
779    if(firstFire.index>1000 && firstFire.index<1100)
780    {
781      System.out.println("fire: "+firstFire);
782    }
783    
784    //System.out.println("fire: "+firstFire);
785
786    //first send out the spikes
787    for(int i=0 ; i < (neurons[firstFire.index].getAxon()).branches.length;
788      i++)
789    {
790      // if(firstFire.index==0)
791      // {
792      //   System.out.println (
793      //     neurons [ firstFire.index ]
794      //       .getAxon ( ).branches [ i ].synapses.length );
795      // }
796
797      inputQueue.insertItem (
798        new InputEvent (
799          firstFire.time
800            + ( neurons [ firstFire.index ].getAxon ( ) ).branches [ i ]
801              .delay,
802          ( neurons [ firstFire.index ].getAxon ( ) ).branches [ i ],
803          firstFire.index ) );
804    }
805    
806    double timeOfNextEvent;
807    
808    // neuron do fire
809    if( (timeOfNextEvent=neurons[firstFire.index].updateFire()) >=0.0 )
810    {
811
812      tmp_firetime=firstFire.time+ timeOfNextEvent;
813        //neurons[firstFire.index].timeOfFire();
814      neurons[firstFire.index].setTimeOfNextFire(tmp_firetime);
815      
816      //insert this into the new firing queue;      
817      fireQueue.insertItem(new FireEvent(firstFire.index, tmp_firetime));
818    }
819    else
820    {
821      //if the neuron doesn't fire    
822      neurons[firstFire.index].setTimeOfNextFire(-1);
823    }
824    fireQueue.deleteItem(firstFire); //delete this item
825    }
826    */
827
828    /***********************************************************************
829    * Process the event from fireQueue in parallel.
830    ***********************************************************************/
831    public void  pFireProcess ( final FireEvent  firstFireEvent )
832      throws jpvmException, Exception
833    ////////////////////////////////////////////////////////////////////////
834    {
835      final int  adjustedNeuronIndex = firstFireEvent.index - base;
836      
837      final Neuron  neuron = neurons [ adjustedNeuronIndex ];
838      
839      /*
840      p.println("fire t:"+firstFire.time+" index:"+firstFire.index);
841      fireQueue.show(p);
842      inputQueue.show(p);
843      poissonQueue.show(p);
844      */
845
846      double  tmp_firetime;
847      
848      // only neuron really fires
849      
850      if ( neuron.realFire ( ) )
851      {
852        // int host;
853
854        // if the neuron is recordable
855        
856        if ( neuron.getRecord ( ) )
857        {
858          // p.println(firstFire.index+" recorded");
859          
860          recordBuff.buff.add (
861            new NetRecordSpike (
862              firstFireEvent.time,
863              firstFireEvent.index ) );
864        }
865        
866/*
867        if ( firstFire.index != neurons.length + base - 1
868          && firstFire.index > 1000
869          && firstFire.index < 1100 ) //don't record special neurons
870        {
871          jpvmBuffer buff = new jpvmBuffer ( );
872          
873          buff.pack (
874            new NetRecordSpike (
875              localTime,
876              firstFire.time,
877              firstFire.index ) );
878              
879          info.jpvm.pvm_send (
880            buff,
881            info.parent,
882            NetMessageTag.gatherFire );
883        }
884*/
885        // first send out the spikes
886        // int i=0;
887        // try
888        // {
889        //   System.out.println (
890        //     "neuron:"+(firstFire.index-base)+" fire:"+firstFire.time);
891
892        long  target = neuron.getTHost ( );
893        
894        for ( int  i = 0; i < info.numTasks; i++ )
895        {
896          if ( ( target & ( 1L << i ) ) != 0 ) // it has target at host i
897          {
898            if ( i == info.idIndex ) // localhost 
899            {
900              final Integer
901                axonIndex = Integer.valueOf ( firstFireEvent.index );
902              
903              final Axon  axon = axons.get ( axonIndex );
904              
905              final int  axonBranchesLength = axon.branches.length;
906              
907              for ( int  iter = 0; iter < axonBranchesLength; iter++ )
908              {
909                final Branch  branch = axon.branches [ iter ];
910                
911                inputEventSlot.offer (
912                  new InputEvent (
913                    firstFireEvent.time + branch.delay,
914                    branch,
915                    firstFireEvent.index ) );
916              }
917            }
918            else // remote host
919            {
920              spikeBuffers [ i ].buff.add (
921                new NetMessage (
922                  firstFireEvent.time,
923                  firstFireEvent.index ) );
924            }
925          }
926        }
927
928        // }
929        // catch ( ArrayIndexOutOfBoundsException  e )
930        // {
931        //   p.println ( "firstFire.index-base:"+firstFire.index+"-"+base
932        //     +"="+(firstFire.index-base)+" uplimit"+neurons.length
933        //     +" branch_length"
934        //     +neurons[firstFire.index-base].getAxon().branches.length
935        //     +" curr "+i + "synapse empty"
936        //     + ( ( neurons [ firstFire.index - base ].getAxon ( ) )
937        //       .branches[i].synapses==null)
938        //     + " syn:"
939        //     + ( ( neurons [ firstFire.index - base ].getAxon ( ) )
940        //       .branches[i].synapses.length ) );
941        //
942        //   e.printStackTrace ( p );
943        // }
944      }
945      
946      double timeOfNextEvent;
947      
948      // neuron do fire
949      
950      if ( ( timeOfNextEvent = neuron.updateFire ( ) ) >= 0 )
951      {
952        tmp_firetime = firstFireEvent.time + timeOfNextEvent;
953        
954        // neurons[firstFire.index-base].timeOfFire();
955        
956        // insert this into the new firing queue;
957        
958        fireQueue.insertItem (
959          new FireEvent (
960            firstFireEvent.index,
961            tmp_firetime ) );
962        
963        neuron.setTimeOfNextFire ( tmp_firetime );
964      }
965      else
966      {
967        // if the neuron doesn't fire
968        
969        neuron.setTimeOfNextFire ( -1 );
970      }
971      
972      // delete this item
973      
974      fireQueue.deleteItem ( firstFireEvent );
975    }
976
977    @SuppressWarnings("unused")
978    @Deprecated
979    public void  pMainProcess (
980      FireEvent firstFire,
981      double    freq,
982      double    weight,
983      Seed      seed)
984    ////////////////////////////////////////////////////////////////////////
985    {
986      //
987    }
988
989    /***********************************************************************
990    * process the event from (internal) inputQueue
991    * 
992    * @param firstInput 
993    ***********************************************************************/
994    @Deprecated
995    public void  inputProcess ( InputEvent  firstInput )
996    ////////////////////////////////////////////////////////////////////////
997    {
998      double tmp_firetime;
999      
1000      //System.out.println("input: "+firstInput);
1001      
1002      // first delete the false prediction
1003      
1004      //System.out.println("input:"+firstInput);
1005      
1006      for ( int i = 0; i < firstInput.branch.synapses.length ; i++)
1007      {
1008        // if ( firstInput.branch.synapses [ i ].to == 8300 )
1009        // {
1010        //   System.out.println("find trace"+firstInput+" 8300");
1011        // }
1012        
1013        // if last time predicts the neuron will fire in future
1014        
1015        // TODO:  requires cleanup
1016        
1017        if ( neurons [
1018          firstInput.branch.synapses [ i ].getTargetNeuronIndex ( ) ]
1019          .getTimeOfNextFire ( ) != -1 )
1020        {
1021          // System.out.println (
1022          //   new FireEvent (
1023          //     firstInput.branch.synapses[i].to,
1024          //     neurons [ firstInput.branch.synapses [ i ].to ]
1025          //       .getTimeOfNextFire ( ) ) );
1026          
1027          fireQueue.deleteItem (
1028            new FireEvent (
1029              firstInput.branch.synapses [ i ].getTargetNeuronIndex ( ),
1030              neurons [ firstInput.branch.synapses [ i ].getTargetNeuronIndex ( ) ]
1031                .getTimeOfNextFire ( ) ) );
1032        }
1033
1034        double timeOfNextEvent;
1035        
1036        // neuron do fire
1037        
1038        if ( ( timeOfNextEvent
1039          = neurons [ firstInput.branch.synapses [ i ]
1040            .getTargetNeuronIndex ( ) ].updateInput (
1041            firstInput.time,
1042            firstInput.branch.synapses [ i ] ) ) >= 0.0 )
1043        {
1044          tmp_firetime = firstInput.time + timeOfNextEvent;
1045          
1046          //neurons[firstInput.branch.synapses[i].to].timeOfFire();
1047          
1048          neurons [ firstInput.branch.synapses [ i ]
1049            .getTargetNeuronIndex ( ) ]
1050            .setTimeOfNextFire ( tmp_firetime );
1051          
1052          //insert this into the new firing queue;
1053          
1054          fireQueue.insertItem (
1055            new FireEvent (
1056              firstInput.branch.synapses [ i ].getTargetNeuronIndex ( ),
1057              tmp_firetime));
1058        }
1059        else
1060        {
1061          // if the neuron doesn't fire
1062          
1063          neurons [ firstInput.branch.synapses [ i ]
1064            .getTargetNeuronIndex ( ) ]
1065            .setTimeOfNextFire ( -1 );
1066        }
1067      }
1068      
1069      // delete this item
1070      
1071      inputQueue.deleteItem ( firstInput );
1072    }
1073
1074    /***********************************************************************
1075    * poisson input process  
1076    ***********************************************************************/
1077    @Deprecated
1078    public void  poissonProcess(PInputEvent poiInput)
1079    ////////////////////////////////////////////////////////////////////////
1080    {
1081      double tmp_firetime;
1082      
1083      // if last time predicts the neuron will fire in future
1084      
1085      if ( neurons [ poiInput.synapse.getTargetNeuronIndex ( ) ]
1086        .getTimeOfNextFire ( ) != -1 )
1087      {
1088        // System.out.println (
1089        //   new FireEvent (
1090        //     firstInput.branch.synapses [ i ].to,
1091        //     neurons [ firstInput.branch.synapses [ i ].to ]
1092        //       .getTimeOfNextFire ( ) ) );
1093        
1094        fireQueue.deleteItem (
1095          new FireEvent (
1096            poiInput.synapse.getTargetNeuronIndex ( ),
1097            neurons [ poiInput.synapse.getTargetNeuronIndex ( ) ]
1098              .getTimeOfNextFire ( ) ) );
1099      }
1100
1101      double  timeOfNextEvent;
1102      
1103      // neuron do fire
1104      
1105      if ( ( timeOfNextEvent
1106        = neurons [ poiInput.synapse.getTargetNeuronIndex ( ) ]
1107          .updateInput (
1108        poiInput.time,
1109        poiInput.synapse ) ) >=0.0 )
1110      {
1111        tmp_firetime = poiInput.time + timeOfNextEvent;
1112        
1113        // neurons[poiInput.synapse.to].timeOfFire();
1114        
1115        neurons [ poiInput.synapse.getTargetNeuronIndex ( ) ]
1116          .setTimeOfNextFire ( tmp_firetime );
1117        
1118        // insert this into the new firing queue;
1119        
1120        fireQueue.insertItem (
1121          new FireEvent (
1122            poiInput.synapse.getTargetNeuronIndex ( ),
1123            tmp_firetime ) );
1124      }
1125      else
1126      {
1127        // if the neuron doesn't fire
1128        
1129        neurons [ poiInput.synapse.getTargetNeuronIndex ( ) ]
1130          .setTimeOfNextFire ( -1 );
1131      }
1132      
1133      poissonQueue.insertItem (
1134        new PInputEvent (
1135          poiInput.time + ( -Math.log ( Cnsran.ran2 ( seed ) )
1136            / simulatorParser.backgroundFrequency ),
1137          poiInput.synapse,
1138          -1 ) );
1139      
1140      // delete this item
1141      
1142      poissonQueue.deleteItem ( poiInput );
1143    }
1144
1145    /***********************************************************************
1146    * poisson input process (external input) in parallel 
1147    ***********************************************************************/
1148    public void  pPoissonProcess ( PInputEvent  poiInput )
1149    ////////////////////////////////////////////////////////////////////////
1150    {
1151      final int  targetNeuronIndex
1152        = poiInput.synapse.getTargetNeuronIndex ( ) - base;
1153      
1154      final Neuron  targetNeuron = neurons [ targetNeuronIndex ];
1155      
1156      //  p.println("t:"+poiInput.time+" sourceID:"+poiInput.sourceId
1157      //    +" id"+poiInput.synapse.to+" syn:"+poiInput.synapse);
1158      //  p.flush();
1159      //  fireQueue.show(p);
1160      //  inputQueue.show(p);
1161      //  poissonQueue.show(p);
1162      
1163      final double  timeOfNextFire = targetNeuron.getTimeOfNextFire ( );
1164
1165      if ( timeOfNextFire != -1 )
1166      {
1167        // if last time predicts the neuron will fire in future
1168        
1169        fireQueue.deleteItem (
1170          new FireEvent (
1171            poiInput.synapse.getTargetNeuronIndex ( ),
1172            targetNeuron.getTimeOfNextFire ( ) ) );
1173      }
1174
1175      final double
1176        timeOfNextEvent = targetNeuron.updateInput (
1177          poiInput.time,
1178          poiInput.synapse );
1179      
1180      // neuron do fire
1181      
1182      if ( timeOfNextEvent >= 0.0 )
1183      {
1184        //  p.println("neuron fire");
1185        //  p.flush();
1186        
1187        final double
1188          tmp_firetime = poiInput.time + timeOfNextEvent;
1189        
1190        //neurons[poiInput.synapse.to-base].timeOfFire();
1191        
1192        // insert this into the new firing queue
1193        
1194        fireEventSlot.offer (
1195          new FireEvent (
1196            poiInput.synapse.getTargetNeuronIndex ( ),
1197            tmp_firetime ) );
1198        
1199        targetNeuron.setTimeOfNextFire ( tmp_firetime );
1200        
1201        //  p.println("neuron time called");
1202        //  p.flush();
1203      }
1204      else
1205      {
1206        //  p.println("neuron doesn't fire");
1207        //  p.flush();
1208        
1209        // if the neuron doesn't fire
1210        
1211        targetNeuron.setTimeOfNextFire ( -1 );
1212      }
1213      
1214      //  p.println("input is updated");
1215      //  p.flush();
1216      
1217      if ( poiInput.sourceId == -1 )
1218      {
1219        poissonQueue.insertItem (
1220          new PInputEvent (
1221            poiInput.time + ( -Math.log ( Cnsran.ran2 ( seed ) )
1222              / simulatorParser.backgroundFrequency ),
1223            poiInput.synapse,
1224            -1 ) );
1225      }
1226      else
1227      {
1228        final SubExp
1229          subExp = experiment.subExp [ subExpId ];
1230        
1231        final Stimulus
1232          stimulus = subExp.stimuli [ poiInput.sourceId ];
1233        
1234        final double  timeOfNext
1235          = stimulus.getNextTime ( poiInput.time );
1236        
1237        if ( timeOfNext >= 0 )
1238        {
1239          //p.println("t:"+timeOfNext+" sourceID:"+poiInput.sourceId
1240          //+" id"+poiInput.synapse.to);
1241          
1242          poissonQueue.insertItem (
1243            new PInputEvent (
1244              timeOfNext,
1245              poiInput.synapse,
1246              poiInput.sourceId ) );
1247        }
1248      }
1249      
1250      // delete this item
1251      
1252      poissonQueue.deleteItem ( poiInput );
1253    }
1254
1255    /***********************************************************************
1256    * Process the event from inputQueue in parallel.
1257    ***********************************************************************/
1258    public void  pInputProcess ( final InputEvent  firstInputEvent )
1259    ////////////////////////////////////////////////////////////////////////
1260    {
1261      //  p.println("INPUT");
1262      //  fireQueue.show(p);
1263      //  inputQueue.show(p);
1264      //  poissonQueue.show(p);
1265      
1266      for ( final Synapse  synapse : firstInputEvent.branch.synapses )
1267      {
1268        // if(firstInput.branch.synapses[i].to==8300)
1269        // p.println("find trace"+firstInput+" 8300");
1270        
1271        // TODO:  rename to adjustedTargetNeuronIndex
1272        
1273        final int
1274          targetNeuronIndex = synapse.getTargetNeuronIndex ( ) - base;
1275        
1276        final Neuron  targetNeuron = neurons [ targetNeuronIndex ];
1277        
1278        // if last time predicts the neuron will fire in future
1279        
1280        final double  timeOfNextFire = targetNeuron.getTimeOfNextFire ( ); 
1281        
1282        if ( timeOfNextFire != -1 )
1283        {
1284          fireQueue.deleteItem (
1285            new FireEvent (
1286              synapse.getTargetNeuronIndex ( ),
1287              timeOfNextFire ) );
1288        }
1289
1290        final double  timeOfNextEvent = targetNeuron.updateInput (
1291          firstInputEvent.time,
1292          synapse );        
1293        
1294        // neuron do fire
1295        
1296        if ( timeOfNextEvent >= 0.0 )
1297        {
1298          final double
1299            tmp_firetime = firstInputEvent.time + timeOfNextEvent;
1300          
1301          // neurons[firstInput.branch.synapses[i].to-base].timeOfFire();
1302          
1303          // insert this into the new firing queue;
1304          
1305          fireQueue.insertItem (
1306            new FireEvent (
1307              synapse.getTargetNeuronIndex ( ),
1308              tmp_firetime ) );
1309          
1310          targetNeuron.setTimeOfNextFire ( tmp_firetime );
1311        }
1312        else
1313        {
1314          // if the neuron doesn't fire
1315          
1316          targetNeuron.setTimeOfNextFire ( -1 );
1317        }
1318      }
1319      
1320      // delete this item
1321      
1322      inputQueue.deleteItem ( firstInputEvent );
1323    }
1324    
1325/*
1326    public void testRun()
1327    ////////////////////////////////////////////////////////////////////////
1328    {
1329    FireEvent firstFire;
1330    InputEvent firstInput;
1331    PInputEvent poiInput;
1332    double minTime;
1333    double fireTime, inputTime, pInputTime;
1334//    System.out.println("before running...");
1335
1336//    inputQueue.show();
1337
1338    while(!stop)
1339    {
1340      // take out the first fire element
1341      firstFire =  fireQueue.firstItem();
1342      // take out the first input element
1343      firstInput =  inputQueue.firstItem();
1344      // take out the first poisson input element
1345      poiInput =  poissonQueue.firstItem();
1346
1347//      System.out.println("running...");
1348
1349      if(firstFire != null)
1350      {
1351        fireTime=firstFire.time;
1352      }
1353      else
1354      {
1355        fireTime=Double.MAX_VALUE;
1356      }
1357
1358      if(firstInput != null)
1359      {
1360        inputTime=firstInput.time;
1361      }
1362      else
1363      {
1364        inputTime=Double.MAX_VALUE;
1365      }
1366
1367      if(poiInput != null)
1368      {
1369        pInputTime=poiInput.time;
1370      }
1371      else
1372      {
1373        pInputTime=Double.MAX_VALUE;
1374      }
1375
1376      minTime = ( fireTime < inputTime? fireTime: inputTime); 
1377      minTime = (minTime < pInputTime? minTime: pInputTime);
1378
1379      if( firstFire != null && minTime == firstFire.time) //fire event
1380      {
1381//        System.out.println("fire.."+firstFire);
1382        fireProcess(firstFire);
1383
1384      }
1385      // input event
1386      else if ( firstInput !=null && minTime == firstInput.time)
1387      {
1388        //        System.out.println("input..");
1389        inputProcess(firstInput);
1390      }
1391      // poissoninput event
1392      else if (  poiInput !=null && minTime == poiInput.time)
1393      {
1394//        System.out.println("background: "+poiInput.synapse.to);
1395        poissonProcess(poiInput);
1396      }
1397    }
1398    }
1399*/
1400    
1401    ////////////////////////////////////////////////////////////////////////
1402    // private methods
1403    ////////////////////////////////////////////////////////////////////////
1404    
1405    private void  clearModulationFactors ( )
1406    ////////////////////////////////////////////////////////////////////////
1407    {
1408      if ( modulatedSynapseSeq == null )
1409      {
1410        return;
1411      }
1412      
1413      final int  size = modulatedSynapseSeq.size ( );
1414      
1415      for ( int  i = 0; i < size; i++ )
1416      {
1417        final ModulatedSynapse
1418          modulatedSynapse = modulatedSynapseSeq.get ( i );
1419        
1420        modulatedSynapse.clearModulationFactors ( );
1421      }
1422    }
1423    
1424    ////////////////////////////////////////////////////////////////////////
1425    ////////////////////////////////////////////////////////////////////////
1426    }