unit Equations2;

interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, TeEngine, Series, ExtCtrls, TeeProcs, Chart, Math,
  DDSpinEdit,
  Unit1,Unit2,Stimulation;

var
    { Variables }
    t,U,w,K,Na,nu,xD,m,V,dVdt
                                                :double;
    { Parameters }
    dt,Cm,tau_w,gI_gE,tau_K,ro_pump,tau_xD,dxD_reset,tau_m,tau_Na,
    g_U,gE,gL,C,
    I_stim,I_a,k1,Gain,u0,uu,nu_max,
    UT,U_reset,dw_reset,dNa_reset,dK_reset,roK_roNa,
    U1,U2,V0, NoiseAmpl,INaKpump,
    Nai_alpha,Ko_alpha,VK,VK0,VKnorm,K_bath,K0,Na0,DB
                                                :double;
    nt,nt_end,n_Write,n_Draw
                                                :integer;
    aaa,bbb                                     :text;
    Stim                                        :TStim;


procedure Cleaning;
procedure PlotSigmoid;
procedure Integrate;
function dexp(x :double) :double;
function Sigmoid(x :double) :double;
function Sigmoid2(x :double) :double;
function Sigmoid3(x :double) :double;
function Theta(x :double) :double;
function step(a,b :double) :double;    { step = a**b }
function max(x,y:double):double;

implementation


function dexp(x :double) :double;
begin
  if      x<-20 then dexp:=0{exp(-20)}
  else if x> 20 then dexp:=exp( 20)
  else               dexp:=exp(x);
end;

function Sigmoid(x :double) :double;
begin    Sigmoid:=1/(1+dexp(-x))  end;

function Sigmoid2(x :double) :double;
begin    Sigmoid2:=2/(1+dexp(-2*x)) - 1;  end;

function Sigmoid3(x :double) :double;
begin
  if      x<0 then Sigmoid3:=0
  else if x<1 then Sigmoid3:=x
  else             Sigmoid3:=1;
end;

function Theta(x :double) :double;
begin if x>=0 then Theta:=1 else Theta:=0; end;

function step(a,b :double) :double;    { step = a**b }
begin
  step:=exp(b*ln(a));
end;

function max(x,y:double):double;
begin  if x>y then max:=x  else max:=y;  end;

procedure Parameters;
{ Basic parameters are from Izhikevich, p. 295 }
begin
  dt :=Form1.DDSpinEdit1.Value;
  Cm :=Form1.DDSpinEdit2.Value;
  g_U:=Form1.DDSpinEdit3.Value;
  n_Write:=trunc(Form1.DDSpinEdit4.Value);
  n_Draw :=trunc(Form1.DDSpinEdit19.Value);
  gE :=Form1.DDSpinEdit5.Value;
  I_a      :=Form1.DDSpinEdit7.Value;
  UT       :=Form1.DDSpinEdit8.Value;
  U_reset  :=Form1.DDSpinEdit9.Value;
  dw_reset :=Form1.DDSpinEdit10.Value;
  dK_reset :=Form1.DDSpinEdit14.Value;
  k1       :=Form1.DDSpinEdit15.Value;
  dNa_reset:=Form1.DDSpinEdit16.Value;
  tau_w  :=Form1.DDSpinEdit11.Value;
  gI_gE  :=Form1.DDSpinEdit12.Value;
  tau_K  :=Form1.DDSpinEdit13.Value;
  ro_pump:=Form1.DDSpinEdit17.Value;
  DB     :=Form1.DDSpinEdit20.Value;
  tau_xD :=Form1.DDSpinEdit21.Value;
  dxD_reset:=Form1.DDSpinEdit22.Value;
  Gain   :=Form1.DDSpinEdit23.Value;
  u0     :=Form1.DDSpinEdit24.Value;
  NoiseAmpl:=Form1.DDSpinEdit25.Value;
  tau_m  :=Form1.DDSpinEdit26.Value;
  tau_Na :=Form1.DDSpinEdit27.Value;
  roK_roNa:=Form1.DDSpinEdit28.Value;
  K0     :=Form1.DDSpinEdit29.Value;
  gL     :=Form1.DDSpinEdit30.Value;
  C      :=Form1.DDSpinEdit31.Value;
//  U1:=-5/2/g_U-sqrt(5/4/g_U/g_U-140/g_U);
//  U2:=-5/2/g_U+sqrt(25/4/g_U/g_U-140/g_U);
  U1:=-60; {mV}
  U2:=-40; {mV}
  V0:=-70; {mV}
  Nai_alpha:=20 {mM};
  Ko_alpha:=2.5 {mM};
  K_bath:=Form1.DDSpinEdit18.Value; // 8.5 {mM};
  nu_max:=100 {Hz};
end;

procedure InitialConditions;
begin
  U:=V0;
  w:=0;
  K:=K0;
  VK0   :=26.6{mV}*ln({K}K0/130{mM});
  VKnorm:=26.6{mV}*ln(3{mM}/130{mM});
  Na0:=10;
  Na:=Na0;
  m:=0;
  xD:=1;
  nu:=0;
  V:=0;      dVdt:=0;
  Stim:=TStim.Create;
  { Randomize }
  RandSeed:=2;
end;

procedure Cleaning;
begin
 { Cleaning }
  Form1.Series1.Clear;
  Form1.Series2.Clear;
  Form1.Series3.Clear;
  Form1.Series4.Clear;
  Form1.Series5.Clear;
  Form1.Series6.Clear;
  Form1.Series7.Clear;
  Form1.LineSeries1.Clear;
  Form1.LineSeries2.Clear;
  Form1.LineSeries3.Clear;
  Form1.LineSeries5.Clear;
  Form1.Series7.Active:=(tau_m>0);
  Form2.LineSeries6.Clear;
end;

procedure PlotSigmoid;
var i :integer;
begin
  assignFile(bbb,'Sigmoid.dat'); rewrite(bbb);
  Form1.LineSeries4.Clear;
  Parameters;
  for i:=0 to 150 do begin
      uu:=i;
      if Form1.CheckBox1.Checked then nu:=nu_max*max(Sigmoid3((uu-u0)/Gain),0)
                                 else nu:=nu_max*max(Sigmoid2((uu-u0)/Gain),0);
      Form1.LineSeries4.AddXY(uu,nu);
      writeln(bbb,uu:8:3,' ',nu:8:3);
  end;
  Application.ProcessMessages;
  close(bbb);
end;

procedure Writing;
begin
      { Writing }
      {           1             2         3                                    }
      write  (aaa,nt*dt:8:3,' ',U:8:3,' ',w:8:3,' ');
      {           4          5                          6                      }
      write  (aaa,U2:8:3,' ',INaKpump*1e3{mM/s}:8:3,' ',uu:8:3,' ');
      {           7           8          9                                     }
      write  (aaa,nu :8:3,' ',V :8:3,' ',K :8:3,' ');
      {           10          11          12                                   }
      write  (aaa,Na :8:3,' ',xD :8:3,' ',Stim.Current :8:3,' ');
      {           13                 14                                          }
      writeln(aaa,nt*dt/1000:8:3,' ',Stim.Rate :8:3);
end;

procedure Integrate;
var
    dUdt,dwdt,dKdt,dNadt,dxDdt,dmdt,I_ex,I_in,y
                                              :double;
begin
  Parameters;
  InitialConditions;
  Cleaning;
  PlotSigmoid;
  assignFile(aaa,'t_U_w_U2_pump_uu_nu_m_K_Na_xD.dat'); rewrite(aaa);
  nt:=0;
  repeat nt:=nt+1;  t:=nt*dt;
    Parameters;
    VK:=26.6{mV}*ln(K/130{mM});
    { Na-K pump, [Wei 2014] }
    INaKpump:=ro_pump/(1+dexp(3.5-K))/(1+dexp((25-Na)/3));    {M/s}
    { Stimulation }
    Stim.Stimulate(t,dt);
    I_stim  :=(VK-VKnorm)*k1 + NoiseAmpl/sqrt(dt)*randG(0,1) + Stim.Current; // sqrt is introduced on 26.09.2017
    I_ex:=       gE*m*xD;
    I_in:=-gI_gE*gE*m;  if I_stim+I_ex+I_in>DB then I_in:=0;
    { Total current }
    uu      :=I_stim + I_ex + I_in{gE*m*(xD-0.5)} - INaKpump;     // !!!  Na-K-pump is new since 22.05.2018
    { Izhikevich *************************************}
    dUdt :=1/Cm    *(g_U*(U-U1)*(U-U2) - w + uu + I_a);
    dwdt :=1/tau_w *(0-w);
    { Sigmoid ****************************************************************}
    y:=uu;
    if Form1.CheckBox3.Checked { with V-equation } then y:=V;
    if Form1.CheckBox1.Checked then  nu:=nu_max*    Sigmoid3((y-u0)/Gain)
                               else  nu:=nu_max*max(Sigmoid2((y-u0)/Gain),0);
    { Main eqs. **************************************************************}
    dKdt :=1/tau_K *(K_bath-K) - 2*roK_roNa*INaKpump + dK_reset *(nu{+Stim.Rate})/1000;
    dNadt:=1/tau_Na*(Na0-Na)   - 3*         INaKpump + dNa_reset*(nu+Stim.Rate)/1000;
    if tau_m=0 then m:=nu else
    dmdt :=1/tau_m *(nu-m);
    dxDdt:=1/tau_xD*(1-xD)                  - dxD_reset*nu*xD/1000;
    dVdt :=1/C*(-gL*V + uu);
    {*************************************************************************}
    U :=U +dt*dUdt;
    w :=w +dt*dwdt;
    K :=K +dt*dKdt;     K:=max(0,K);
    Na:=Na+dt*dNadt;
    m :=m +dt*dmdt;
    xD:=xD+dt*dxDdt;
    V :=V +dt*dVdt;
    {****************************************************************}
    { Drawing }
    if (U>=UT) then begin
       n_Write:=1;  n_Draw:=1;
    end;
    if nt mod n_Draw = 0 then begin
       Form1.Series1.AddXY(nt*dt,U);
       Form1.Series2.AddXY(nt*dt,w);
       Form1.Series3.AddXY(nt*dt,U2);
       Form1.Series4.AddXY(nt*dt,INaKpump);
       Form1.Series5.AddXY(nt*dt,uu);
       Form1.Series6.AddXY(nt*dt,nu);
       if tau_m>0 then
       Form1.Series7.AddXY(nt*dt,m);
       Form1.LineSeries1.AddXY(nt*dt,K);
       Form1.LineSeries2.AddXY(nt*dt,Na);
       Form1.LineSeries3.AddXY(nt*dt,xD);
       Form1.LineSeries5.AddXY(nt*dt,V);
       Form2.LineSeries6.AddXY(nt*dt,max(Stim.Current,Stim.Rate));
    end;
    if nt mod 1000*n_Draw = 0 then  Application.ProcessMessages;
    if (nt mod n_Write = 0) or (Stim.Status='Pulse') then  Writing;
    {****************************************************************}
    { Reset }
    if (U>=UT) then begin
       U :=U_reset;
       w :=w  + dw_reset;
    end;
    nt_end:=trunc(Form1.DDSpinEdit6.Value/dt);
  until nt>=nt_end;
  Application.ProcessMessages;
  closeFile(aaa);
end;

end.