001 package cnslab.cnsnetwork; 002 003 import java.io.*; 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 * Implemented simple integrate and fire neuron. Only two channels are 014 * allowed, one excitatory and one inhibitory, and the decay of 015 * inhibitory channel should be longer than the excitatory one. 016 * Look up table is used for quick spike test. 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 026 ***********************************************************************/ 027 public class SIFNeuron 028 implements Neuron, Serializable 029 //////////////////////////////////////////////////////////////////////// 030 //////////////////////////////////////////////////////////////////////// 031 { 032 033 private static final long serialVersionUID = 0L; 034 035 public static double maxWeight = 0; 036 037 /** For table size */ 038 public static int TABLESIZE_o = 40; 039 040 /** For table size */ 041 public static int TABLESIZE_c = 500; 042 043 /** For table min boundary */ 044 public static double memMin = -0.10; // min -100 mV membrane potential 045 046 /** For table max boundary */ 047 public static double memMax = -0.04; // max -40 mV membrane potential 048 049 /** For table min boundary */ 050 public static double [ ] 051 currMin = new double [ ] { 0, -maxWeight }; // minimum Current 052 053 /** For table max boundary */ 054 public static double [ ] 055 currMax = new double [ ] { maxWeight, 0 }; 056 057 /** For table step size */ 058 public static double memStep = ( memMax - memMin ) / TABLESIZE_o; 059 060 /** For table step size */ 061 public static double currStep = ( maxWeight ) / TABLESIZE_c; 062 063 // absoulte refractory period 064 // public static final double para.ABSREF = 0.000; 065 066 // voltage from threshold for which the neuron is considered to fire 067 // public static final double para.EPSV = 1E-14; 068 069 // used for absoulte refractory period 070 // public double timeOffset=0.0; 071 072 /** long imposes a constraint on the maximum number of hosts to be 64 */ 073 public long tHost; 074 075 // private static variables 076 077 private static final Class<SIFNeuron> 078 CLASS = SIFNeuron.class; 079 080 private static final Logger 081 LOGGER = LoggerFactory.getLogger ( CLASS ); 082 083 // private final variables 084 085 private final SIFNeuronPara para; 086 087 // private non-final variables 088 089 private double [ ] curr; 090 091 /** true then this neuron will be recorded */ 092 private boolean record; 093 094 /** the neuron membrane potential */ 095 private double memV; 096 097 /** time of the neuron's next fire */ 098 private double timeOfNextFire = -1; 099 100 /** time of the neuron's last update */ 101 private double timeOfLastUpdate; 102 103 //////////////////////////////////////////////////////////////////////// 104 // static methods 105 //////////////////////////////////////////////////////////////////////// 106 107/* 108 public static double maxWeight() 109 //////////////////////////////////////////////////////////////////////// 110 { 111 return para.CAP*(para.THRESHOLD-para.VRESET)/para.MINRISETIME; 112 } 113*/ 114 115 //////////////////////////////////////////////////////////////////////// 116 // constructor methods 117 //////////////////////////////////////////////////////////////////////// 118 119 public SIFNeuron ( final SIFNeuronPara para ) 120 //////////////////////////////////////////////////////////////////////// 121 { 122 if ( maxWeight 123 < para.CAP * ( para.THRESHOLD - para.VRESET ) / para.MINRISETIME ) 124 { 125 maxWeight 126 = para.CAP * ( para.THRESHOLD - para.VRESET ) / para.MINRISETIME; 127 128 currStep = maxWeight / TABLESIZE_c; 129 } 130 131 this.para = para; 132 133 this.curr = new double [ 2 ]; 134 135 curr[0]=0.0; 136 137 curr[1]=0.0; 138 139 if ( !para.GlobalInit ) 140 { 141 para.FIRETABLE = new boolean 142 [ TABLESIZE_o + 1 ] 143 [ TABLESIZE_c + 1 ] 144 [ TABLESIZE_c + 1 ]; 145 146 for ( int i = 0; i < TABLESIZE_o + 1; i++ ) 147 { 148 for ( int k = 0; k < TABLESIZE_c + 1; k++ ) 149 { 150 for ( int m = 0; m < TABLESIZE_c + 1; m++ ) 151 { 152 this.memV = i * memStep + memMin; 153 154 this.curr = new double [ ] { 155 k * currStep + currMin [ 0 ], 156 m * currStep + currMin [ 1 ] }; 157 158 if ( this.memV >= para.THRESHOLD ) 159 { 160 para.FIRETABLE [ i ] [ k ] [ m ] = true; 161 } 162 else 163 { 164 if ( doesFire ( ) ) 165 { 166 para.FIRETABLE [ i ] [ k ] [ m ] = true; 167 } 168 else 169 { 170 para.FIRETABLE [ i ] [ k ] [ m ] = false; 171 } 172 } 173 } 174 } 175 } 176 177 para.GlobalInit = true; 178 } 179 } 180 181 //////////////////////////////////////////////////////////////////////// 182 // interface Neuron accessor methods 183 //////////////////////////////////////////////////////////////////////// 184 185/* 186 public Axon getAxon() 187 //////////////////////////////////////////////////////////////////////// 188 { 189 return axon; 190 } 191*/ 192 193 @Override 194 public double [ ] getCurr ( double currTime ) 195 //////////////////////////////////////////////////////////////////////// 196 { 197 return new double [ ] { 198 curr [ 0 ] * Math.exp ( 199 -para.DECAY_E * ( currTime - timeOfLastUpdate ) ), 200 curr [ 1 ] * Math.exp ( 201 -para.DECAY_I * ( currTime - timeOfLastUpdate ) ) }; 202 } 203 204 @Override 205 public double getMemV ( final double currTime ) 206 //////////////////////////////////////////////////////////////////////// 207 { 208 // if input comes inside the refractory period, memV not changed 209 210 if ( currTime < timeOfLastUpdate ) 211 { 212 return this.memV; 213 } 214 215 return voltageFunOfTime ( currTime - timeOfLastUpdate ); 216 } 217 218 @Override 219 public boolean getRecord ( ) 220 //////////////////////////////////////////////////////////////////////// 221 { 222 return this.record; 223 } 224 225 @Override 226 public long getTHost ( ) 227 //////////////////////////////////////////////////////////////////////// 228 { 229 return tHost; 230 } 231 232 /*********************************************************************** 233 * get the value of timeOfNextFire 234 * 235 * @return 236 * the value of timeOfNextFire 237 ***********************************************************************/ 238 @Override 239 public synchronized double getTimeOfNextFire ( ) 240 //////////////////////////////////////////////////////////////////////// 241 { 242 return this.timeOfNextFire; 243 } 244 245 @Override 246 public boolean isSensory ( ) 247 //////////////////////////////////////////////////////////////////////// 248 { 249 return false; 250 } 251 252 @Override 253 public boolean realFire() 254 //////////////////////////////////////////////////////////////////////// 255 { 256 return true; 257 } 258 259 //////////////////////////////////////////////////////////////////////// 260 // additional accessor methods 261 //////////////////////////////////////////////////////////////////////// 262 263 /*********************************************************************** 264 * It looks this was originally a method in the Neuron interface which 265 * has since been removed. Probably can be deleted. 266 ***********************************************************************/ 267 public double getSensoryWeight ( ) 268 //////////////////////////////////////////////////////////////////////// 269 { 270 throw new RuntimeException("LIF neurons can't run this function"); 271 } 272 273 /*********************************************************************** 274 * get the value of timeOfLastUpdate 275 * 276 * @return 277 * the value of timeOfLastUpdate 278 ***********************************************************************/ 279 public double getTimeOfLastUpdate ( ) 280 //////////////////////////////////////////////////////////////////////// 281 { 282 return this.timeOfLastUpdate; 283 } 284 285 //////////////////////////////////////////////////////////////////////// 286 // interface Neuron mutator methods 287 //////////////////////////////////////////////////////////////////////// 288 289 /*********************************************************************** 290 * set a new value to memV 291 * 292 * @param memV 293 * the new value to be used 294 ***********************************************************************/ 295 public void setMemV ( final double memV ) 296 //////////////////////////////////////////////////////////////////////// 297 { 298 this.memV = memV; 299 } 300 301 /*********************************************************************** 302 * set the neuron record or not. 303 ***********************************************************************/ 304 @Override 305 public void setRecord ( final boolean record ) 306 //////////////////////////////////////////////////////////////////////// 307 { 308 this.record = record; 309 } 310 311 /*********************************************************************** 312 * set the target host id //0 means none , 1 means yes 313 ***********************************************************************/ 314 @Override 315 public void setTHost(long id) 316 //////////////////////////////////////////////////////////////////////// 317 { 318 this.tHost=id; 319 } 320 321 /*********************************************************************** 322 * set a new value to timeOfNextFire 323 * 324 * @param timeOfNextFire 325 * the new value to be used 326 ***********************************************************************/ 327 @Override 328 public synchronized void setTimeOfNextFire ( 329 final double timeOfNextFire ) 330 //////////////////////////////////////////////////////////////////////// 331 { 332 this.timeOfNextFire = timeOfNextFire; 333 } 334 335 //////////////////////////////////////////////////////////////////////// 336 // additional mutator methods 337 //////////////////////////////////////////////////////////////////////// 338 339 /*********************************************************************** 340 * set a new value to timeOfLastUpdate 341 * 342 * @param timeOfLastUpdate 343 * the new value to be used 344 ***********************************************************************/ 345 public void setTimeOfLastUpdate ( final double timeOfLastUpdate ) 346 //////////////////////////////////////////////////////////////////////// 347 { 348 this.timeOfLastUpdate = timeOfLastUpdate; 349 } 350 351 //////////////////////////////////////////////////////////////////////// 352 // interface Neuron lifecycle methods 353 //////////////////////////////////////////////////////////////////////// 354 355 @Override 356 public void init ( 357 int expid, 358 int trialid, 359 Seed idum, 360 Network net, 361 int id) 362 //////////////////////////////////////////////////////////////////////// 363 { 364 this.timeOfLastUpdate=0.0; 365 366 this.timeOfNextFire=-1; 367 368 this.memV = para.ini_mem+para.ini_memVar*Cnsran.ran2(idum); 369 370 this.curr[0]=0.0; 371 372 this.curr[1]=0.0; 373 374 double fireTime; 375 376 // net.p.println("My name is"+net.getClass().getName()); 377 378 if ( doesFire ( ) ) 379 { 380 final Slot<FireEvent> fireEventSlot = net.getFireEventSlot ( ); 381 382 if ( net.getClass ( ).getName ( ).equals ( 383 "cnslab.cnsnetwork.ANetwork" ) ) 384 { 385 fireEventSlot.offer ( 386 new AFireEvent ( 387 id, 388 fireTime = timeOfFire ( 0 ), 389 net.info.idIndex, 390 ( ( ANetwork ) net ).aData.getId ( ( ANetwork ) net ) ) ); 391 } 392 else if ( net.getClass ( ).getName ( ).equals ( 393 "cnslab.cnsnetwork.Network" ) ) 394 { 395 fireEventSlot.offer ( 396 new FireEvent ( 397 id, 398 fireTime = timeOfFire ( 0 ) ) ); 399 } 400 else 401 { 402 throw new RuntimeException ( 403 "Other Network Class doesn't exist" ); 404 } 405 406 timeOfNextFire = fireTime; 407 } 408 } 409 410 @Override 411 public double updateFire ( ) 412 //////////////////////////////////////////////////////////////////////// 413 { 414 // LOGGER.trace ( "updateFire() entered" ); 415 416 memV = para.VRESET; 417 418 // LOGGER.debug ( "time of next fire: {}", timeOfNextFire ); 419 420 // LOGGER.debug ( "time of last update: {}", timeOfLastUpdate ); 421 422 // LOGGER.debug ( "excitatory current: {}", curr [ 0 ] ); 423 424 curr [ 0 ] 425 = curr [ 0 ] 426 * Math.exp ( 427 -para.DECAY_E * ( timeOfNextFire - timeOfLastUpdate ) ) 428 - para.REFCURR; 429 430 // LOGGER.debug ( "excitatory current: {}", curr [ 0 ] ); 431 432 // LOGGER.debug ( "inhibitory current: {}", curr [ 1 ] ); 433 434 curr [ 1 ] *= Math.exp ( 435 -para.DECAY_I * ( timeOfNextFire - timeOfLastUpdate ) ); 436 437 // LOGGER.debug ( "inhibitory current: {}", curr [ 1 ] ); 438 439 timeOfLastUpdate = timeOfNextFire + para.ABSREF; 440 441 curr [ 0 ] *= Math.exp ( -para.DECAY_E * para.ABSREF ); 442 443 // LOGGER.debug ( "excitatory current: {}", curr [ 0 ] ); 444 445 curr [ 1 ] *= Math.exp ( -para.DECAY_I * para.ABSREF ); 446 447 // LOGGER.debug ( "inhibitory current: {}", curr [ 1 ] ); 448 449 //curr[a]=para.IRATIO[a]*curr[a]*Math.exp( 450 // -para.DECAY[a]*(timeOfNextFire-timeOfLastUpdate+para.ABSREF)) 451 // +para.IADD[a]*Math.exp(-para.DECAY[a]*para.ABSREF); 452 453 // for excitatory neuron 454 // curr[0] =0; 455 456 final int 457 memI = ( int ) ( Math.floor ( ( memV - memMin ) / memStep ) ); 458 459 final int [ ] curI = new int [ curr.length ]; 460 461 for ( int i = 0; i < curr.length; i++ ) 462 { 463 curI [ i ] = ( int ) 464 ( Math.floor ( ( curr [ i ] - currMin [ i ] ) / currStep ) ); 465 } 466 467 int [ ] memList = null; 468 469 final int [ ] [ ] currList = new int [ curr.length ] [ ]; 470 471 boolean fullcheck = false; 472 473 if ( memI < 0) 474 { 475 fullcheck = true; 476 // memList = new int [] {0} ; 477 } 478 else if ( memI >= TABLESIZE_o ) 479 { 480 fullcheck = true; 481 // memList = new int [] {TABLESIZE_o} ; 482 } 483 else 484 { 485 memList = new int [ ] { memI, memI + 1 }; 486 } 487 488 for ( int i = 0; i < curr.length; i++ ) 489 { 490 if ( curI [ i ] < 0 ) 491 { 492 fullcheck = true; 493 // currList[i] = new int [] {0} ; 494 } 495 else if ( curI [ i ] == TABLESIZE_c ) 496 { 497 if ( i == 0 ) 498 { 499 fullcheck = true; //excitatory currents needs to be checked 500 } 501 else 502 { 503 // inhibitory currents is fine 504 505 currList [ i ] = new int [ ] { TABLESIZE_c }; 506 } 507 } 508 else if ( curI [ i ] > TABLESIZE_c ) 509 { 510 fullcheck = true; 511 } 512 else 513 { 514 currList [ i ] = new int [ ] { curI [ i ], curI [ i ] + 1 }; 515 } 516 } 517 518 if ( fullcheck ) 519 { 520 if ( doesFire ( ) ) 521 { 522 return timeOfFire ( timeOfNextFire ); 523 } 524 525 return -1.0; 526 } 527 528 final boolean fireS = para.FIRETABLE 529 [ memList [ 0 ] ] 530 [ currList [ 0 ] [ 0 ] ] 531 [ currList [ 1 ] [ 0 ] ]; 532 533 for ( int ii = 0; ii < memList.length; ii++ ) 534 { 535 for ( int kk = 0; kk < currList [ 0 ].length; kk++ ) 536 { 537 for ( int mm = 0; mm < currList [ 1 ].length; mm++ ) 538 { 539 if ( !( ii == 0 540 && kk == 0 541 && mm == 0 ) ) 542 { 543 if ( ( para.FIRETABLE 544 [ memList [ ii ] ] 545 [ currList [ 0 ] [ kk ] ] 546 [ currList [ 1 ] [ mm ] ] ^ fireS ) ) 547 { 548 // ambiguous firing case, do a full check 549 550 if ( doesFire ( ) ) 551 { 552 return timeOfFire ( timeOfNextFire ); 553 } 554 555 return -1.0; 556 } 557 } 558 } 559 } 560 } 561 562 // pass through this, it is non ambiguous now. 563 564 if ( fireS ) //do fire 565 { 566 return timeOfFire(timeOfNextFire); 567 } 568 569 // not fire 570 571 return -1.0; 572 } 573 574 @Override 575 public double updateInput ( 576 final double time, 577 final Synapse inputSynapse ) 578 //////////////////////////////////////////////////////////////////////// 579 { 580 // if input comes inside the refractory period only update current to 581 // the last update time. 582 583 if ( time < timeOfLastUpdate ) 584 { 585 switch ( inputSynapse.getType ( ) ) 586 { 587 case 0: 588 589 curr [ 0 ] = curr [ 0 ] 590 + Math.exp ( -para.DECAY_E * ( timeOfLastUpdate - time ) ) 591 * inputSynapse.getWeight ( ); 592 593 // if(timeOfLastUpdate - time <=0 ) 594 // throw new RuntimeException( 595 // "reversed time at "+time+"lastUPdate "+timeOfLastUpdate 596 // +" input:"+input.toString()); 597 598 // if( curr[0]>1.0 ) 599 // throw new RuntimeException( 600 // "two high activity time at "+time+"lastUPdate " 601 // +timeOfLastUpdate+" input:"+input.toString()); 602 603 break; 604 605 case 1: 606 607 curr [ 1 ] = curr [ 1 ] 608 + Math.exp ( -para.DECAY_I * ( timeOfLastUpdate - time ) ) 609 * inputSynapse.getWeight ( ); 610 611 break; 612 613 default: 614 615 System.out.println("no other types available"); 616 617 break; 618 } 619 } 620 else 621 { 622 memV = voltageFunOfTime(time - timeOfLastUpdate); 623 624 if(memV-para.THRESHOLD>0) 625 { 626 System.out.println( 627 "current time:"+time+" last update: "+timeOfLastUpdate 628 +" time of next firing: "+timeOfNextFire); 629 630 System.out.println("time diff:"+(time - timeOfLastUpdate)); 631 632 System.out.println("curr0:"+curr[0]+" curr1:"+curr[1]); 633 634 System.out.println("Membrane voltage: "+memV); 635 636 throw new RuntimeException ( 637 "current time:"+time 638 +" last update: "+timeOfLastUpdate 639 +" time of next firing: "+timeOfNextFire + "\n" 640 +"time diff:"+(time - timeOfLastUpdate)+"\n" 641 +"curr0:"+curr[0]+" curr1:"+curr[1]+"\n" 642 +"Membrane voltage: "+memV+"\n" 643 +"already fires in updateinput" ); 644 } 645 646 switch ( inputSynapse.getType ( ) ) 647 { 648 case 0: 649 650 curr[0]=curr[0] 651 *Math.exp(-para.DECAY_E*(time - timeOfLastUpdate)) 652 +inputSynapse.getWeight ( ); 653 654 curr[1]=curr[1] 655 *Math.exp(-para.DECAY_I*(time - timeOfLastUpdate)); 656 657 break; 658 659 case 1: 660 661 curr[0] = curr[0] 662 * Math.exp(-para.DECAY_E*(time - timeOfLastUpdate)); 663 664 curr[1] = curr[1] 665 * Math.exp(-para.DECAY_I*(time - timeOfLastUpdate)) 666 + inputSynapse.getWeight ( ); 667 668 break; 669 670 default: 671 672 System.out.println("no other types available"); 673 674 break; 675 } 676 677 timeOfLastUpdate = time; 678 } 679 680 int memI = (int)(Math.floor((memV-memMin)/memStep)); 681 682 int [] curI = new int [curr.length]; 683 684 for(int i=0; i < curr.length; i++) 685 { 686 curI[i] = (int)(Math.floor((curr[i]-currMin[i])/currStep)); 687 } 688 689 int [] memList=null; 690 691 int [][] currList = new int [curr.length][]; 692 693 boolean fullcheck = false; 694 695 if(memI<0) 696 { 697 fullcheck = true; 698 699 // memList = new int [] {0} ; 700 } 701 else if( memI >= TABLESIZE_o ) 702 { 703 fullcheck = true; 704 705 // memList = new int [] {TABLESIZE_o} ; 706 } 707 else 708 { 709 memList = new int [] {memI, memI+1} ; 710 } 711 712 for(int i=0; i < curr.length; i++) 713 { 714 if(curI[i]<0) 715 { 716 fullcheck = true; 717 718 // currList[i] = new int [] {0} ; 719 } 720 else if( curI[i] == TABLESIZE_c ) 721 { 722 if(i==0) 723 { 724 fullcheck = true; //excitatory currents needs to be checked 725 } 726 else 727 { 728 // inhibitory currents is fine 729 currList[i] = new int [] {TABLESIZE_c} ; 730 } 731 } 732 else if( curI[i] > TABLESIZE_c ) 733 { 734 fullcheck = true; 735 } 736 else 737 { 738 currList[i] = new int [] {curI[i],curI[i]+1} ; 739 } 740 } 741 742 if(fullcheck) 743 { 744 if(doesFire()) 745 { 746 return timeOfFire(time); 747 } 748 return -1.0; 749 } 750 751 final boolean fireS = para.FIRETABLE 752 [ memList [ 0 ] ] 753 [ currList [ 0 ] [ 0 ] ] 754 [ currList [ 1 ] [ 0 ] ]; 755 756 for(int ii=0; ii < memList.length; ii ++) 757 { 758 for(int kk=0; kk< currList[0].length; kk++) 759 { 760 for(int mm=0; mm< currList[1].length; mm++) 761 { 762 if(!(ii==0 && kk==0 && mm==0)) 763 { 764 if ( ( para.FIRETABLE 765 [ memList [ ii ] ] 766 [ currList [ 0 ] [ kk ] ] 767 [ currList [ 1 ] [ mm ] ] ^ fireS ) ) 768 { 769 // ambiguous firing case, do a full check 770 771 if(doesFire()) 772 { 773 return timeOfFire(time); 774 } 775 776 return -1.0; 777 } 778 } 779 } 780 } 781 } 782 783 //pass through this, it is non ambiguous now. 784 785 if(fireS) //do fire 786 { 787 return timeOfFire(time); 788 } 789 790 // not fire 791 792 return -1.0; 793 } 794 795 //////////////////////////////////////////////////////////////////////// 796 // additional methods 797 //////////////////////////////////////////////////////////////////////// 798 799 /*********************************************************************** 800 * @return 801 * true if the neuron will fire in future 802 ***********************************************************************/ 803 public boolean doesFire ( ) 804 //////////////////////////////////////////////////////////////////////// 805 { 806 double ts = 0.0; 807 808 double dt, tsmax; 809 810 int i = 0, imax; 811 812 // maximum time to look for firing 813 814 tsmax = 3.0 * ( para.DECAY_E > para.CAP / para.GL 815 ? para.DECAY_E : para.CAP / para.GL ); 816 817 // tsmax=2*(para.CAP/para.GL);//maximum time to look for firing 818 819 // max number of steps to look for firing 820 821 imax = 100000; 822 823// TODO: Should this be >= instead of >? memV >= para.THRESHOLD 824 825 if ( memV - para.THRESHOLD > 0 ) 826 { 827 System.out.println ( 828 "last update " 829 + timeOfLastUpdate 830 + "time of next firing " 831 + timeOfNextFire ); 832 833 System.out.println ( "Membrane voltage: " + memV ); 834 835 throw new RuntimeException ( "already fires in doesfire" ); 836 } 837 838 // if(derivvoltageFunOfTime(ts)<0)return false; 839 840 while ( ts < tsmax ) 841 { 842 if ( deriVoltageFunOfTime ( ts ) <= 0 ) 843 { 844 return false; 845 } 846 847 dt = ( para.THRESHOLD - voltageFunOfTime ( ts ) ) 848 / deriVoltageFunOfTime ( ts ); 849 850 if ( voltageFunOfTime ( ts + 2 * dt ) > para.THRESHOLD ) 851 { 852 // guess=ts+2*dt; 853 854 return true; 855 } 856 857 ts += dt; 858 859 if ( voltageFunOfTime ( ts ) > para.THRESHOLD ) 860 { 861 // guess = ts; 862 863 return true; 864 } 865 866 i++; 867 868 if ( i > imax ) 869 { 870 throw new RuntimeException ( 871 "max steps reached in doesfire, memV=" 872 + memV + " curr=" + curr [ 0 ] + " " + curr [ 1 ] ); 873 } 874 } 875 876 return false; 877 } 878 879 /*********************************************************************** 880 * @return 881 * the time when the neuron fires 882 ***********************************************************************/ 883 public double timeOfFire ( final double currTime ) 884 //////////////////////////////////////////////////////////////////////// 885 { 886 double ts = 0; 887 888 // double dt; 889 890 int 891 i = 0, 892 imax = 100000; 893 894 while ( i < imax ) 895 { 896 ts += ( para.THRESHOLD - voltageFunOfTime ( ts ) ) 897 / deriVoltageFunOfTime ( ts ); 898 899 if ( Math.abs ( 1 - ( voltageFunOfTime ( ts ) / para.THRESHOLD ) ) 900 < para.EPSV ) 901 { 902 return ts + ( ( timeOfLastUpdate - currTime ) < 0 ? 0.0 903 : ( timeOfLastUpdate - currTime ) ); 904 } 905 906 i++; 907 } 908 909 throw new RuntimeException ( 910 "Too many iteratations were encounted in timeOfFire currtime:" 911 + currTime 912 + " timeOfLastUpdate:" 913 + timeOfLastUpdate 914 + " curr[0]:" 915 + curr [ 0 ] 916 + " curr[1]:" 917 + curr [ 1 ] 918 + " memV:" 919 + memV 920 + " timeOfnextFire:" 921 + timeOfNextFire ); 922 } 923 924 //////////////////////////////////////////////////////////////////////// 925 // overridden Object methods 926 //////////////////////////////////////////////////////////////////////// 927 928 @Override 929 public String toString ( ) 930 //////////////////////////////////////////////////////////////////////// 931 { 932 String tmp = ""; 933 934 tmp = tmp + "MemVol:" + memV + "\n"; 935 936 tmp = tmp + "Current:" + "\n"; 937 938 for ( int i = 0; i < curr.length; i++) 939 { 940 tmp = tmp + " curr" + i + " " + curr [ 0 ] + "\n"; 941 } 942 943 // tmp = tmp + axon; 944 945 return tmp; 946 } 947 948 //////////////////////////////////////////////////////////////////////// 949 // private methods 950 //////////////////////////////////////////////////////////////////////// 951 952 /*********************************************************************** 953 * @param _diff 954 * time difference between current time and future time 955 * @return 956 * derivative of membrane voltage with respect to time 957 ***********************************************************************/ 958 private double deriVoltageFunOfTime ( final double _diff ) 959 //////////////////////////////////////////////////////////////////////// 960 { 961 return ( 962 ( curr [ 0 ] * para.DECAY_E ) 963 / ( Math.exp ( para.DECAY_E * _diff ) 964 * ( para.CAP * para.DECAY_E - para.GL ) ) 965 + ( curr [ 1 ] * para.DECAY_I ) 966 / ( Math.exp ( para.DECAY_I * _diff ) 967 * ( para.CAP * para.DECAY_I - para.GL ) ) 968 - ( para.GL 969 * ( curr [ 0 ] / ( para.CAP * para.DECAY_E - para.GL ) 970 + curr [ 1 ] / ( para.CAP * para.DECAY_I - para.GL ) 971 + memV 972 - para.VREST ) ) 973 / ( para.CAP * Math.exp ( ( para.GL * _diff ) / para.CAP ) ) ); 974 } 975 976 /*********************************************************************** 977 * @param _diff 978 * time difference between current time and future time 979 * @return 980 * membrane voltage 981 ***********************************************************************/ 982 private double voltageFunOfTime ( double _diff ) 983 //////////////////////////////////////////////////////////////////////// 984 { 985 return ( 986 -curr [ 0 ] 987 / ( Math.exp ( para.DECAY_E * _diff ) 988 * ( para.CAP * para.DECAY_E - para.GL ) ) 989 - curr [ 1 ] 990 / ( Math.exp ( para.DECAY_I * _diff ) 991 * ( para.CAP * para.DECAY_I - para.GL ) ) 992 + ( curr [ 0 ] / ( para.CAP * para.DECAY_E - para.GL ) 993 + curr [ 1 ] / ( para.CAP * para.DECAY_I - para.GL ) 994 + memV - para.VREST ) 995 / Math.exp ( ( para.GL * _diff ) / para.CAP ) 996 + para.VREST ); 997 } 998 999 //////////////////////////////////////////////////////////////////////// 1000 //////////////////////////////////////////////////////////////////////// 1001 }