//load_file("nrngui.hoc")
load_file("./fixnseg.hoc")
/*
begintemplate Location
public secRef, loc, distToRootCenter
objref secRef

proc init() {
	secRef = new SectionRef()
	loc = $1
	secRef.root distance(0,0.5)
	secRef.sec distToRootCenter = distance(loc)
}
endtemplate Location
*/
begintemplate cell10

public init, topol, subsets, init_pas, geom_nseg_shared, basic_shape, init_active
public axon, section, soma

create axon[1], section[1], soma[1]
objref somaLoc,somaBorderLoc,blebLoc,distalDendLoc,proxDendLoc,synDendLoc,spineCount,this,synlist
objref rates_soma, rates_axon, ratefile, rates_sec

func lambda_f() { local i, x1, x2, d1, d2, lam
        if (n3d() < 2) {
                return 1e5*sqrt(diam/(4*PI*$1*Ra*cm))
        }
// above was too inaccurate with large variation in 3d diameter
// so now we use all 3-d points to get a better approximate lambda
        x1 = arc3d(0)
        d1 = diam3d(0)
        lam = 0
        for i=1, n3d()-1 {
                x2 = arc3d(i)
                d2 = diam3d(i)
                lam += (x2 - x1)/sqrt(d1 + d2)
                x1 = x2   d1 = d2
        }
        //  length of the section in units of lambda
        lam *= sqrt(2) * 1e-5*sqrt(4*PI*$1*Ra*cm)

        return L/lam
}

proc geom_nseg_shared() {
  area(0.5) // make sure diam reflects 3d points
  if (numarg()==0){freq=def_freq}else{freq=$1}
  forall { 
	//if (debug_mode)
    if (debug_mode) printf("lambda=%g\n",lambda_f(freq))
  	nseg = int((L/(d_lambda*lambda_f(freq))+0.9)/2)*2 + 1
  }

}

func tempScale() {
	// $1: Q10
	return $1^((celsius-24)/10)
}

func fsigm() {
    // $1: x
    // $2: amplitude
    // $3: center
    // $4: slope
    return $2-$2/(1.0+exp(($1-$3)/$4))
}

func gna_func() {
    /*
    Returns Nav conductance density (gNa) along the axon.

    Arguments:
    $1 x       -- Axonal distance from soma
    $2 gNas    -- Somatic gNa
    $3 gNaa    -- Axonal density
    $4 a0      -- Scaling factor
    $5 lambda2 -- Axonal decay length constant

    Returns:
    Axonal gNa
    */
    lambda1 = 5.0 // default 5.0
    lambda2 = 10
    return $2 + ($3-$2) * (1.0-exp(-$1/lambda1)) * (1.0 + $4*exp(-$1/lambda2))
}



proc init_pas() {local Ra_soma, Ra_axon, i, dist
    Ra_soma = 200
    Ra_axon = 120
    forall {
	insert pas
	e_pas=-80
	cm = 1.00 * tempScale(q10_cm)// * scale_spines
	g_pas = 2.5e-5 * tempScale(q10_g_pas)// * scale_spines
	Ra = 200.0 * tempScale(q10_Ra)
    }
    somaLoc.secRef.sec { distance(0,0) }
    for i=0, n_axon-1 axon[i] {
		dist = distance(0.5)
		Ra = (Ra_soma - fsigm(dist, Ra_soma-Ra_axon, 100, 50)) * tempScale(q10_Ra) 
    }
}


proc basic_shape() {local i, soma_rad, soma_lhalf, soma_part0, soma_part1, diam0, diam1, soma_diam0, delta, axon_diam1
    n_sections = 2 + 4 + 8 + 16
    create section[n_sections]
    if (has_bleb == 1) {
        n_axon = 7
    } else {
        n_axon = 9
    }
    create axon[n_axon]
    // Set nseg to something > 1 so that
    // the tapering works
    for i=0, n_axon-1 axon[i] { nseg=5 }
    n_soma = 21
    create soma[n_soma]
    
    soma_rad = 5
    soma_lhalf = 10
    offset = 0.15 // offset to prevent soma from tapering too much
    // elliptic soma:
    for i=0, n_soma-1 soma[i] {
	L = soma_lhalf * 2.0/n_soma
	soma_part0 = (-1.0 + 2.0*(i+offset/2.0)/ (n_soma+offset) ) * soma_lhalf * 0.98
	soma_part1 = (-1.0 + 2.0*(i+1+offset/2.0)/ (n_soma+offset) ) * soma_lhalf * 0.98
	diam0 = sqrt((1 - soma_part0*soma_part0/ (soma_lhalf*soma_lhalf)) * soma_rad*soma_rad) * 2.0
	diam1 = sqrt((1 - soma_part1*soma_part1/ (soma_lhalf*soma_lhalf)) * soma_rad*soma_rad) * 2.0
	diam(0:1) = diam0:diam1
	if (i==0) {
            soma_diam0 = diam0
        }
    }
    
    axon[0] { diam(0:1)=soma_diam0:axon_diam0 L = 8 }
    
    // linear taper:
    axon_diam1 = 0.3
    delta = (axon_diam0-axon_diam1) / 20.0
    for i=1,5 axon[i] {
        L = 4 
        diam(0:1)=axon_diam0-(i-1)*delta*L : axon_diam0-i*delta*L
    }

    if (has_bleb == 1) {
	axon[6] { 
            diam = 2.0
            L = 2.0
            blebLoc = new Location(0.0)
        }
	
    } else {
	axon[6] { 
            diam = axon_diam1 L = 500  //2500
            blebLoc = new Location(0.0)
        }
	// mfb
	axon[7] { 
            diam = 0.3 // 3.0 // 0.4
            L = 500 // 2500
        }
	axon[8] { diam = axon_diam1 L = 470 } //2470
    }

    for i=0,1 section[i]  { diam(0:1)=soma[n_soma-1].diam(1.0):2.0 L=20 }
    for i=2,5 section[i]  { diam(0:1)=2.0:1.5 L=80 }
    for i=6,13 section[i] { diam = 0.9 L=100 }
    for i=14,n_sections-1 section[i] { diam=0.6 L=100 }
    
    // define soma:
    soma[n_soma/2.0]  somaLoc = new Location(0.5)
    soma[0] somaBorderLoc = new Location(0.0)

    // define dendritic sites:
    section[n_sections-1] distalDendLoc = new Location(0.8)
    section[1] proxDendLoc = new Location(0.05)
    section[n_sections-5] synDendLoc = new Location(0.8)
    
    access somaLoc.secRef.sec
}

proc topol() {local i
    basic_shape()
    for i=0,1 section[i] { connect section[i](0.0), soma[n_soma-1](1.0) }
    for i=2,n_sections-1 section[i] { connect section[i](0.0), section[int((i-2)/2.0)](1.0) }
    for i=1, n_soma-1 soma[i] { connect soma[i](0.0), soma[i-1](1.0) }
    connect axon[0](0.0), soma[0](0.0)
    for i=1, n_axon-1 axon[i] { connect axon[i](0.0), axon[i-1](1.0) }
    //init_spines()
}

objref all,den,axo,som
proc subsets() {local i
    all = new SectionList()
    for i=0, n_sections-1 section[i] all.append()
    for i=0, n_axon-1 axon[i] all.append()
    for i=0, n_soma-1 soma[i] all.append()
    den = new SectionList()
    for i=0, n_sections-1 section[i] den.append()
    axo = new SectionList()
    for i=0, n_axon-1 axon[i] axo.append()
    som = new SectionList()
    for i=0, n_soma-1 soma[i] som.append()
}

proc init_active() {
  forall{
  	insert na8st
  	insert KI
    ena=75
  	ek=-95
  }
	rates_soma=new Vector(18)
	rates_axon=new Vector(18)
	rates_sec=new Vector(18)
	ratefile=new File()

	ratefile.ropen("soma_st8.txt")
	rates_soma.scanf(ratefile)
	ratefile.close()
	ratefile.ropen("axon_st8.txt")
	rates_axon.scanf(ratefile)
	ratefile.close()

	somaBorderLoc.secRef.sec {distance()}
	forsec axo{
		
    for (ns,0) { 
    	dist=distance(ns)
  		for i=0,17 {
  			rates_sec.x[i]=fsigm(dist,(rates_axon.x[i] - rates_soma.x[i]), 4,2) + rates_soma.x[i]
  		}
  		a1_0_na8st(ns) = rates_sec.x[0]
  		a1_1_na8st(ns) = rates_sec.x[1]
  			    
  		b1_0_na8st(ns) = rates_sec.x[2]
  		b1_1_na8st(ns) = rates_sec.x[3]
  			
  		a2_0_na8st(ns) = rates_sec.x[4]
  		a2_1_na8st(ns) = rates_sec.x[5]
  			    
  		b2_0_na8st(ns) = rates_sec.x[6]
  		b2_1_na8st(ns) = rates_sec.x[7]
  			
  		a3_0_na8st(ns) = rates_sec.x[8]
  		a3_1_na8st(ns) = rates_sec.x[9]
  			    
  		b3_0_na8st(ns) = rates_sec.x[10]
  		b3_1_na8st(ns) = rates_sec.x[11]
  	
  		bh_0_na8st(ns) = rates_sec.x[12]
  		bh_1_na8st(ns) = rates_sec.x[13]
  		bh_2_na8st(ns) = rates_sec.x[14]
  	
  		ah_0_na8st(ns) = rates_sec.x[15]
  		ah_1_na8st(ns) = rates_sec.x[16]
  		ah_2_na8st(ns) = rates_sec.x[17]
  
  		scale_a_KI(ns) *= fsigm(dist,3,4,2)
 
  		gbar_na8st(ns)=gna_func(dist,gna_soma,gna_distal_axon,gna_a0)
      gkbar_KI(ns)=fsigm(dist,(gk_distal_axon-gk_axon),200,100)+gk_axon
    }
    
	}
  forsec som{
    gkbar_KI=gk_soma
    gbar_na8st=gna_soma
  }
  forsec den{
    gkbar_KI=gk_soma
    for (ns) {
      dist=distance(ns)
      gbar_na8st(ns)=fsigm(dist,(gna_distal_dend-gna_soma),80,40)+gna_soma
    }
  }
}  

proc init() {
	verbose    =  1     // 0: no output
	debug_mode =  0     // 0: no debug information (default)

	accuracy   =  0     // 0: compromise between accuracy and simulation speed (default)
	celsius    = 24     // This is to roughly account for the effects of temperature on
	q10_g_pas  =  1.98  // simulations. Passive membrane parameters (Ra, cm, g_pas) 
	q10_Ra     =  0.80  // have no built-in temperature dependence. Instead, they
	q10_cm     =  0.96  // will be scaled when calling membrane.hoc using Q10 values
		                // according to:
		                // Trevelyan AJ, Jack JJB (2002), J Physiol 539:623-636
		                
	has_bleb=0
	axon_diam0 = 1.2                    


	gna_soma = 0.0188
	gna_prox_axon = 0.094
	gna_distal_axon = 0.0386152
	gna_distal_dend = 0.0038
	gna_a0 = 18  // default 18
	gk_axon = 0.004
	gk_soma = 0.004
	gk_distal_axon = 0.010

	def_freq = 1000 //original:100     // Hz, frequency at which AC length constant will be computed
	d_lambda = 0.1 //original:0.1

	topol()
	subsets()
	init_pas()
	geom_nseg_shared()

	for i=0,5 {axon[i].nseg*=3}
  init_active()
}

endtemplate cell10