% Acker et al 2003 model variant neuron network with random connectivity
% with time varying input with LIF-measured stability
% eric zilli - oct ??, 2009
%
% release version 1.0. check modeldb for updates.
%
% this source code is released into the public domain
%
% The Acker et al model is a biophysical model of an entorhinal cortex
% layer II stellate. The model uses voltage-shifted Hodghkin-Huxley loligo
% Na and K channels for spiking, plus a non-inactivating persistent-sodium
% current and a two-component (fast and slow) H-current which are modified
% by Acker et al. from original current models by Erik Fransen. We modify the model by
% scaling down all the conductance densities by increasing the membrane
% capacitance. This slows the minimum firing frequency of the model down so
% that the noise level can be scaled to match our biological data (ISI mean
% 0.2 s, ISI std. dev. 0.036 s).
%
% Interesting questions to continue this research: Setting slowslow=1
% decreases the adaptation's initial magnitude but the effect
% has an effect lasting many ISIs long. Is
% the corresponding time constant model realistic? Experiments looking at H
% current time constants at spiking voltages do not appear to exist, but
% gating variable "friction" in the extended HH model accounts for a
% possible non-zero base for time constants which might play a major role
% here. In-vitro experiments are needed.
% Under what conditions does the ISI period or frequency overshoot and when does it undershoot?
% What is the best way to quantify the history dependence on firing rate
% effect?
% Is it possible for the intrinsic properties of one neuron A to be exactly
% the inverse of B in the sense of this adaptation such that an
% input signal I to A would be distorted by the adaptation into an
% output I' which would then be un-distorted by B to recover a constant function
% of I? (E.g. I goes from driving at 7 Hz to 11 Hz, A's firing rate adapts from
% 11.5 Hz down to 11 Hz. Can there be a B receiving A's spikes that fires at 11 Hz
% given input at 11.5 Hz and which adapts at just the right rate that B continues to
% fire at 11 Hz as the input from A slows down slightly?)
%
% This script starts a network with a specified current level (or
% frequency) and after a specified number of spikes allows the current
% level to be changed. This can be done with a single starting and ending
% current level (Figure S2A-D), a single starting and multiple ending levels
% (Figure S2E-F), multiple starting and single ending level, or a grid of injected
% current levels (Figure S3). These correspond to three types of figures that
% might be of interest.
%
% If the FI curve of the cell or network is known, it can be used to find
% the appropriate current levels. Otherwise they must be set by hand. The
% FI curve needn't be terribly high in resolution, so generating them as
% needed should be quick and easy.
%
% Note: this is a cleaned up version of the script used to generate the
% paper figures--it is possible errors were introduced during the cleaning!
% Feel free to contact me if there is any difficulty reproducing any
% results from the manuscript.
%

clear all;

% type=1 - (Figure S2B,D) class 2 excitable, n=1, noise-free, 1 start, 1 end
% type=2 - (Figure S2F) class 2 excitable, n=1, noise-free, 1 start, 5 end, low-to-high
% type=3 - class 2 excitable, n=1, noise-free, 7:0.5:11 Hz start, 7:0.5:11 Hz end
for type=[3]
  simdur = 10000; % (ms)
  dt = .01; % ms

  nruns =1;

  saveFigures = 0;

  useNoise = 0;
  spikeThreshold = 20; % mV
  slowslow = 0;

  numDropISIs = 10;
  numPreISIs = 10;
  numPostISIs = 10;

  if type==1
    excitationClass = 2;
    useGapJunctions = 1;
    g = 0;
    uniqueNoiseSTD = 0*useNoise;
    ncells = 1;
    pcon = 0;
    load Acker_FI_n1.mat;
    inputMags = interp1(freqs,currents,7,'cubic');
    inputMags2 = interp1(freqs,currents,11,'cubic');
  elseif type==2
    excitationClass = 2;
    useGapJunctions = 1;
    g = 0;
    uniqueNoiseSTD = 0*useNoise;
    ncells = 1;
    pcon = 0;
    load Acker_FI_n1.mat;
    desiredFreqs = 7:11;
    inputMags = interp1(freqs,currents,7,'cubic');
    inputMags2 = interp1(freqs,currents,desiredFreqs,'cubic');
  elseif type==3
    excitationClass = 2;
    useGapJunctions = 1;
    g = 0;
    uniqueNoiseSTD = 0*useNoise;
    ncells = 1;
    pcon = 0;
    load Acker_FI_n1.mat;
    desiredFreqs = [7 11];
    inputMags = interp1(freqs,currents,desiredFreqs,'cubic');
    inputMags2 = interp1(freqs,currents,desiredFreqs,'cubic');
  end

  fileOut = 0;
  typePrefix = [sprintf('%d',excitationClass)];
  if ncells>1
    if useGapJunctions
      typePrefix = [typePrefix 'g'];
    else
      typePrefix = [typePrefix 's'];
    end
  end
  if useNoise
    typePrefix = [typePrefix 'n'];
  end
  outfilename = sprintf('acker_model_%s_history_dependence_%dn_%gnoise_%s.txt',typePrefix,ncells,useNoise,datestr(now,'mmmmdd'));

  % file to save statistics for every individual cell in network, don't
  % save if indivname = ''
  indivname = '';
  % indivname = [strtok(outfilename,'.') '_individualcells.txt'];

  Cm = 5; 1.5; % uF/cm^2
  gNa = 52; % mS/cm^2
  gNap = 0.5; % mS/cm^2
  gH = 1.5; % mS/cm^2
  gK = 11; % mS/cm^2
  gLeak = 0.5; % mS/cm^2
  EH = -20; % (mv)
  ELeak = -65; % (mv)
  EK = -90; % (mv)
  ENa = 55; % (mv)

  slopes = zeros(length(inputMags));
  if length(inputMags)==1 && length(inputMags2)>1
    figISIs = zeros(length(inputMags2),numPreISIs+numPreISIs);
  elseif length(inputMags)>1 && length(inputMags2)==1
    figISIs = zeros(length(inputMags),numPreISIs+numPreISIs);
  elseif length(inputMags)>1 && length(inputMags2)>1
    figISIs = zeros(length(inputMags),length(inputMags2));
  end

  % connectivity matrix
  if pcon==1
    C = 1;
  else
    C = (rand(ncells)<pcon)>0;
    C = sparse(C.*(1-eye(ncells))); % remove autoconnections
  end

  for inputi=1:length(inputMags)
    for inputi2=1:length(inputMags2)

      stabilities = zeros(1,nruns);
      stabilities2 = zeros(1,nruns);
      for run=1:nruns
        % activity of postsynaptic I&F
        npost = 1;
        post = zeros(npost, round(simdur/dt)+1);

        % spike times of postsynaptic I&F
        postspikes = 0;

        % I&F params
        tau = 2.5; % (sec)
        membraneDecay = exp(-dt/tau);
        postWeight=4/ncells;

        % magnitude of noise added to all cells on each step
        commonNoiseSTD = 0;

        numISIs = -1;

        t = 0; % current time in simulation
        tind = 1;

        % initial values
        v = -55*ones(1,ncells);
        mNa = zeros(1,ncells);
        hNa = zeros(1,ncells);
        mNap = zeros(1,ncells);
        nK = zeros(1,ncells);
        mHfast = zeros(1,ncells);
        mHslow = zeros(1,ncells);

        % save state of one cell over simulation:
        state = zeros(2,simdur/dt);

        % binary array indicating which cells fire on each time steps
        spikes = spalloc(ncells, simdur/dt,ncells*simdur); % sparse to save memory in big simulations

        I = inputMags(inputi);
        Is = zeros(1,round(simdur/dt));

        tic
        while t<simdur
          t = t+dt; % advance to next time step
          tind = 1+tind; %round(t/dt);

          %% done below now:
          oldv = v;
          alphamNa = -0.1*(oldv+23)./(exp(-0.1*(oldv+23))-1);
          betamNa = 4*exp(-(oldv+48)/18);
          mNa = mNa + dt*(alphamNa.*(1-mNa) - betamNa.*mNa);

          alphahNa = 0.07*exp(-(oldv+37)/20);
          betahNa = 1./(exp(-0.1*(oldv+7))+1);
          hNa = hNa + dt*(alphahNa.*(1-hNa) - betahNa.*hNa);

          alphanK = -0.01*(oldv+27)./(exp(-0.1*(oldv+27))-1);
          betanK = 0.125*exp(-(oldv+37)/80);
          nK = nK + dt*(alphanK.*(1-nK) - betanK.*nK);

          alphamNap = 1./(0.15*(1+exp(-(oldv+38)/6.5)));
          betamNap = exp(-(oldv+38)/6.5)./(0.15*(1+exp(-(oldv+38)/6.5)));
          mNap = mNap + dt*(alphamNap.*(1-mNap) - betamNap.*mNap);

          minfHfast = 1./(1+exp((oldv+79.2)/9.78));
          mtauHfast = 0.51./(exp((oldv-1.7)/10) + exp(-(oldv+340)/52)) + 1;
          mHfast = mHfast + dt*((minfHfast-mHfast)./mtauHfast);

          minfHslow = 1./(1+exp((oldv+71.3)/7.9));
          if ~slowslow
            mtauHslow = 5.6./(exp((oldv-1.7)/14) + exp(-(oldv+260)/43)) + 1;
          else
            mtauHslow = 65.5813 + 248.0469*exp(-(-79.2190-oldv).^2/33.5178^2);
          end
          mHslow = mHslow + dt*((minfHslow-mHslow)./mtauHslow);

          vnoise = uniqueNoiseSTD*randn(1,ncells);
          if useGapJunctions
            if pcon==0
              v = v + dt*(vnoise - gH*(0.65*mHfast + 0.35*mHslow).*(v-EH) - (gNap*mNap+gNa*mNa.^3.*hNa).*(v-ENa) - gK*nK.^4.*(v-EK) - gLeak*(v-ELeak) + I)/Cm;
            elseif pcon==1
              v = v + dt*(vnoise - gH*(0.65*mHfast + 0.35*mHslow).*(v-EH) - (gNap*mNap+gNa*mNa.^3.*hNa).*(v-ENa) - gK*nK.^4.*(v-EK) - gLeak*(v-ELeak) + I + g*(sum(v)-ncells*v))/Cm;
            else
              vdiffs = repmat(v',ncells,1) - repmat(v,1,ncells);
              v = v + dt*(vnoise - gH*(0.65*mHfast + 0.35*mHslow).*(v-EH) - (gNap*mNap+gNa*mNa.^3.*hNa).*(v-ENa) - gK*nK.^4.*(v-EK) - gLeak*(v-ELeak) + I + g*sum(C*vdiffs,2))/Cm;
            end
          else
            if pcon==0
              v = v + dt*(vnoise - gH*(0.65*mHfast + 0.35*mHslow).*(v-EH) - (gNap*mNap+gNa*mNa.^3.*hNa).*(v-ENa) - gK*nK.^4.*(v-EK) - gLeak*(v-ELeak) + I)/Cm;
            elseif pcon==1
              v = v + dt*(vnoise - gH*(0.65*mHfast + 0.35*mHslow).*(v-EH) - (gNap*mNap+gNa*mNa.^3.*hNa).*(v-ENa) - gK*nK.^4.*(v-EK) - gLeak*(v-ELeak) + I + g*(sum(spikes(:,tind-1),1)-spikes(:,tind-1)'))/Cm;
            else
              v = v + dt*(vnoise - gH*(0.65*mHfast + 0.35*mHslow).*(v-EH) - (gNap*mNap+gNa*mNa.^3.*hNa).*(v-ENa) - gK*nK.^4.*(v-EK) - gLeak*(v-ELeak) + I + g*(C*spikes(:,tind-1))')/Cm;
            end
          end
          state(:,tind) = [v(1) mHslow];

          % spikes if upward crossing spikeThreshold mV
          spikes(:,tind) = (oldv<spikeThreshold).*(v>=spikeThreshold);

          %% do numPreISIs then change I and do numPostISIs
          if any(spikes(:,tind))
            numISIs = numISIs + 1; % starts equal to -1 so second spike is first ISI
          end
          if numISIs<(numPreISIs+numDropISIs)
            I = inputMags(inputi);
          else
            I = inputMags2(inputi2);
          end
          if numISIs==(numPreISIs+numPostISIs+numDropISIs)
            break
          end

          post(:,tind) = post(:,tind-1)*membraneDecay + tau*postWeight*sum(spikes(:,tind));
          % faster(?) if we don't need postspikes:
          post(post(:,tind)>1,tind) = -1e-10;
          % slower way if postspikes is needed:
          %       postspikes(:,tind) = post(:,tind)>1;
          %       post(postspikes(:,tind)>1,tind) = 0; % reset to 0

        end
        toc

        % calculate mean and variance of ISIs for each postsynaptic cell
        npost = 1; %size(post,1);
        ISImeans = zeros(1,npost);
        ISIstds = zeros(1,npost);
        ISIstabilities = zeros(1,nruns);

        %% calculate ISI statistics for each individual unit in the
        %% network:
        indivmeans = zeros(1,ncells);
        indivstds = zeros(1,ncells);
        indivstabilities = zeros(1,ncells);
        ISIs = dt*diff(find(spikes(1,:)>0))/1000;

        if length(inputMags)==1 && length(inputMags2)>1 % add so we can take the average over runs
          figISIs(inputi2,:) = figISIs(inputi2,:) + ISIs((numDropISIs+1):end);
        elseif length(inputMags)>1 && length(inputMags2)==1
          figISIs(inputi,:) = figISIs(inputi,:) + ISIs((numDropISIs+1):end);
        elseif length(inputMags)>1 && length(inputMags2)>1
          % using a complex number to hold two values in one matrix:
          figISIs(inputi2,inputi) = figISIs(inputi2,inputi) + ISIs(numDropISIs+numPreISIs+1) + ISIs(end-1)*i;
        end

        % save to file:
        if fileOut
          fid = fopen(outfilename,'a');
          fprintf(fid,'%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%d\n', ...
            ncells,pcon,inputMags(inputi),inputMags2(inputi2),g,simdur/1000, useNoise*uniqueNoiseSTD,tau,postWeight,...
            mean(ISIs(2:end-numPostISIs-2)), ISIs(end-numPostISIs-2), ISIs(end-numPostISIs+1), ISIs(end-numPostISIs+2),ISIs(end),length(ISIs),...
            (inputMags2(inputi2)-inputMags(inputi)), ISIs(end-numPostISIs+1)-ISIs(end-numPostISIs+2),ISIs(end-numPostISIs+1)-ISIs(end));
          fclose(fid);
        end
        fprintf('%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%d\n', ...
          ncells,pcon,inputMags(inputi),inputMags2(inputi2),g,simdur/1000, useNoise*uniqueNoiseSTD,tau,postWeight,...
          mean(ISIs(2:end-numPostISIs-2)), ISIs(end-numPostISIs-2), ISIs(end-numPostISIs+1), ISIs(end-numPostISIs+2),ISIs(end),length(ISIs),...
          (inputMags2(inputi2)-inputMags(inputi)), ISIs(end-numPostISIs+1)-ISIs(end-numPostISIs+2),ISIs(end-numPostISIs+1)-ISIs(end));

        slopes(inputi,inputi2) = (ISIs(end-numPostISIs-1)-ISIs(end-numPostISIs))/(inputMags2(inputi2)-inputMags(inputi));
      end
    end

    % average ISIs over multiple runs if noisy network is in use:
    if length(inputMags)>1 || length(inputMags2)>1
      figISIs = figISIs./nruns;
    end
  end
end

state = state(:,1:tind);

if length(inputMags)==1 && length(inputMags2)==1
  start=260000;stop=360000;
  figure;
  plot((start:stop)*dt,state(1,start:stop)');
  set(gca,'xlim',[start*dt stop*dt]);
  set(gcf,'position',[82 404 257 185]);
  xlabel('Time (ms)','fontsize',12); ylabel('Voltage (mV)','fontsize',12);
  set(gca,'fontsize',12,'box','off')
  if slowslow
    if saveFigures && exist(['fig_Ackerslow_history_dependence_vtrace_0a.eps'])~=2
      print_eps(['fig_Ackerslow_history_dependence_vtrace_0a.eps'])
      saveas(gcf,['fig_Ackerslow_history_dependence_vtrace_0a.fig'])
    end
  else
    if saveFigures && exist(['fig_Acker_history_dependence_vtrace_0a.eps'])~=2
      print_eps(['fig_Acker_history_dependence_vtrace_0a.eps'])
      saveas(gcf,['fig_Acker_history_dependence_vtrace_0a.fig'])
    end
  end
  figure;
  plot((start:stop)*dt,state(2,start:stop)');
  set(gcf,'position',[82 404 257 227]);
  set(gca,'ygrid','on','xlim',[start*dt stop*dt]);
  xlabel('Time (ms)','fontsize',12); ylabel('Slow H','fontsize',12);
  set(gca,'fontsize',12,'box','off')
  if slowslow
    if saveFigures && exist(['fig_Ackerslow_history_dependence_htrace_0a.eps'])~=2
      print_eps(['fig_Ackerslow_history_dependence_htrace_0a.eps'])
      saveas(gcf,['fig_Ackerslow_history_dependence_htrace_0a.fig'])
    end
  else
    if saveFigures && exist(['fig_Acker_history_dependence_htrace_0a.eps'])~=2
      print_eps(['fig_Acker_history_dependence_htrace_0a.eps'])
      saveas(gcf,['fig_Acker_history_dependence_htrace_0a.fig'])
    end
  end
elseif (length(inputMags)==1 && length(inputMags2)>1) || (length(inputMags)>1 && length(inputMags2)==1)
  figure; plot(1./figISIs','b.-','Markersize',16);
  xlabel('Interspike interval #','fontsize',12); ylabel('1/ISI duration (Hz)','fontsize',12)
  set(gcf,'position',[82 404 257 302])
  set(gca,'ylim',[min(desiredFreqs)-0.1 max(desiredFreqs)+0.5]);
  set(gca,'fontsize',12,'box','off')
  if slowslow
    if saveFigures && exist(['fig_Ackerslow_history_dependence_multi_0a.eps'])~=2
      print_eps(['fig_Ackerslow_history_dependence_multi_0a.eps'])
      saveas(gcf,['fig_Ackerslow_history_dependence_multi_0a.fig'])
    end
  else
    if saveFigures && exist(['fig_Acker_history_dependence_multi_0a.eps'])~=2
      print_eps(['fig_Acker_history_dependence_multi_0a.eps'])
      saveas(gcf,['fig_Acker_history_dependence_multi_0a.fig'])
    end
  end
elseif length(inputMags)>1 && length(inputMags2)>1
  figure; imagesc(desiredFreqs,desiredFreqs,abs(real(figISIs)-imag(figISIs)));
  title('ISI overshoot magnitude (ms)','fontsize',12)
  xlabel('Starting frequency (Hz)','fontsize',12); ylabel('Ending frequency (Hz)','fontsize',12)
  set(gcf,'position',[82 404 322 302])
  set(gca,'fontsize',12,'box','off')
  if saveFigures && exist(['fig_RS' typePrefix '_histdep_ISI_colorplot.eps'])~=2
    print_eps(['fig_RS' typePrefix '_histdep_ISI_colorplot.eps'])
    saveas(gcf,['fig_RS' typePrefix '_histdep_ISI_colorplot.fig'])
  end

  figure; imagesc(desiredFreqs,desiredFreqs,abs(1./real(figISIs)-1./imag(figISIs)));
  title('Frequency overshoot magnitude (Hz)','fontsize',12)
  xlabel('Starting frequency (Hz)','fontsize',12); ylabel('Ending frequency (Hz)','fontsize',12)
  set(gcf,'position',[82 404 322 302])
  set(gca,'fontsize',12,'box','off')
  if saveFigures && exist(['fig_RS' typePrefix '_histdep_freq_colorplot.eps'])~=2
    print_eps(['fig_RS' typePrefix '_histdep_freq_colorplot.eps'])
    saveas(gcf,['fig_RS' typePrefix '_histdep_freq_colorplot.fig'])
  end
end