// Rubinstein model of Ranvier Node's action potentials as in
// Rubinstein JT (1995) Biophys J 68: 779-785.
// Mino H, Rubinstein JT, White JA (2002) Ann Biomed Eng 30: 578-587.
// Bruce IC (2007) Ann Biomed Eng 35: 315-318; 

// Voltage is shifted so that resting voltage = 0 mV (the reversal of the leak)

// This script simulates 1000 sweeps per stimulus and calculates
// firing efficiency, mean firing time and firing time variance
// 100 (nsim) simultaneous sweeps, 10 times
// Lines 69, 109, 110, 162 and 163 are intended to make a voltage trace
// It is advisable to reduce nsim before uncommenting them
//
// Coupled activation particles, 8-state Na channel
// Markov Chain modeling (Chow&White algorithm)

stacksize('max');
nsim=100;
gNa=0.02569*265; //mS/cm2
ENa=144; //mV
Cm=0.0000714*265; Rm=1953.49/265;
Tstop=1; dt=0.001; //ms
Idel=0; Idur=0.1; //µA, ms, ms
threshold=80
points = round(Tstop/dt)
NNa=1000;  //Number of sodium channels

rand('uniform');

// Each row of this matrix represent one of the 20 possible transitions
transitions=[-1 1 0 0 0 0 0 0
1 -1 0 0 0 0 0 0
0 -1 1 0 0 0 0 0
0 1 -1 0 0 0 0 0
0 0 -1 1 0 0 0 0
0 0 1 -1 0 0 0 0
-1 0 0 0 1 0 0 0
1 0 0 0 -1 0 0 0
0 -1 0 0 0 1 0 0
0 1 0 0 0 -1 0 0
0 0 -1 0 0 0 1 0
0 0 1 0 0 0 -1 0
0 0 0 -1 0 0 0 1
0 0 0 1 0 0 0 -1
0 0 0 0 -1 1 0 0
0 0 0 0 1 -1 0 0
0 0 0 0 0 -1 1 0
0 0 0 0 0 1 -1 0
0 0 0 0 0 0 -1 1
0 0 0 0 0 0 1 -1]';

currents=[5:0.1:6.5];

Eff=[];
meanFT=[];
varFT=[];
xx=zeros(1,nsim);
NaNs=[];


tic()
for curr=1:size(currents,'*')
    Iamp=ones(1,nsim)*currents(curr);
    firetimes=[];
    NNaNs=0;
    for nn=1:10
        p=1;
        // Uncomment this only with a small nsim
        // vrec = zeros(points,nsim);
        v = 0*ones(1,nsim);
        alpha_m=1.872*(v-25.41)./(1-exp((25.41-v)/6.06));
        beta_m=3.973*(21-v)./(1-exp((v-21)/9.41));
        M=alpha_m./beta_m;
        beta_h=(22.57)./(1+exp((56-v)/12.5));
        alpha_h=-0.549*(27.74+v)./(1-exp((v+27.74)/9.06));
        H=alpha_h./beta_h;
        //calculation of steady state at t=0
        statesum=(1+H).*(1+M)^3;
        states=round(NNa*[ones(1,nsim);3*M;3*M.^2;M.^3;H;3*M.*H;3*M.^(2).*H;M^(3).*H]./(ones(8,1)*statesum));
        if sum(states,'r')<>ones(1,nsim)*NNa
            states(1,:)=NNa-sum(states(2:8,:),'r');
        end
        rates=[3*alpha_m.*states(1,:)
        beta_m.*states(2,:)
        2*alpha_m.*states(2,:)
        2*beta_m.*states(3,:)
        alpha_m.*states(3,:)
        3*beta_m.*states(4,:)
        alpha_h.*states(1,:)
        beta_h.*states(5,:)
        alpha_h.*states(2,:)
        beta_h.*states(6,:)
        alpha_h.*states(3,:)
        beta_h.*states(7,:)
        alpha_h.*states(4,:)
        beta_h.*states(8,:)
        3*alpha_m.*states(5,:)
        beta_m.*states(6,:)
        2*alpha_m.*states(6,:)
        2*beta_m.*states(7,:)
        alpha_m.*states(7,:)
        3*beta_m.*states(8,:)];
        //time of the next transition (one per each simulation)
        next_ev=-log(1-rand(1,nsim))./sum(rates,'r');
        firetime=zeros(1,nsim);
        firing=zeros(1,nsim);

        for t = dt:dt:Tstop
            //vrec(p,:) = v;  //Uncomment this only with a small nsim
            //p=p+1;
            if or(~firing&v>=threshold) then  //detection of action potentials
                ind=find(v>=threshold&~firing);
                firetime(ind)=t;
                firing(ind)=1;
            end

            Iapp=Iamp*(t>Idel&t<(Idel+Idur));
            Imemb=-Iapp+gNa.*(v-ENa).*states(8,:)/NNa+v./Rm;

            while or(t>=next_ev)  //the use of while (instead of if) allows more than one transition per time step
                //ii contains the indices of the simulations in which a transition is going to occur
                ii=find(t>=next_ev);  
                dist=cumsum(rates./(ones(20,1)*sum(rates,'r')),'r');
                ev=rand(1,nsim);
                for a=ii
                    xx(a)=min(find(ev(a)<dist(:,a)));
                end
                states(:,ii)=states(:,ii)+transitions(:,xx(ii));

                prev_ev=next_ev(ii);
                alpha_m=1.872*(v-25.41)./(1-exp((25.41-v)/6.06));
                beta_m=3.973*(21-v)./(1-exp((v-21)/9.41));
                beta_h=(22.57)./(1+exp((56-v)/12.5));
                alpha_h=-0.549*(27.74+v)./(1-exp((v+27.74)/9.06));

                rates=[3*alpha_m.*states(1,:)
                beta_m.*states(2,:)
                2*alpha_m.*states(2,:)
                2*beta_m.*states(3,:)
                alpha_m.*states(3,:)
                3*beta_m.*states(4,:)
                alpha_h.*states(1,:)
                beta_h.*states(5,:)
                alpha_h.*states(2,:)
                beta_h.*states(6,:)
                alpha_h.*states(3,:)
                beta_h.*states(7,:)
                alpha_h.*states(4,:)
                beta_h.*states(8,:)
                3*alpha_m.*states(5,:)
                beta_m.*states(6,:)
                2*alpha_m.*states(6,:)
                2*beta_m.*states(7,:)
                alpha_m.*states(7,:)
                3*beta_m.*states(8,:)];
                // The next event is calculated from the last event (not from the current time)
                next_ev(ii)=prev_ev-log(1-rand(1,size(ii,'*')))./sum(rates(:,ii),'r');
            end
            v=v-dt*Imemb/Cm;
        end
        printf("round %d Iamp %g\n",nn,currents(curr))
        //clf  //Uncomment this with a small nsim
        //plot(dt:dt:Tstop,vrec)
        firetimes=[firetimes firetime];
        NNaNs=NNaNs + sum(1*(isinf(v)|isnan(v)));
    end
    Eff=[Eff;size(find(firetimes<>0),'*')];
    meanFT=[meanFT;mean(firetimes(find(firetimes<>0)))];
    if size(find(firetimes<>0),'*')>1 then
        varFT=[varFT;variance(firetimes(find(firetimes<>0)))];
    else
        varFT=[varFT;0];
    end
    NaNs=[NaNs;NNaNs];
end
realt=toc();
printf("time = %g\n",realt)
fprintfMat('EffN-Rb8 CW-N'+string(NNa)+'-dt'+string(dt)+'-'+string(realt)+'s.txt',[currents' Eff meanFT varFT NaNs],'%g\t')

scf(0);
clf
subplot(3,1,1)
plot(currents,Eff)
subplot(3,1,2)
plot(currents,meanFT)
subplot(3,1,3)
plot(currents,varFT)