// Contains several utility functions for adding synapses to the GP model.
//          J.R. Edgerton, 2008-2009

// ***************************************************************************
// ***************************** HELPER FUNCTIONS ****************************
// ***************************************************************************
//    --> These functions shouldn't need to be called directly by the user.

// ***************************************************************************
// HELPER FUNCTION calc_syn_integ(float gmax, float tau1, float tau2)
//
// Calculate the time integral for a single synaptic event given
//        tau1, tau2, and gmax.
//         J.R. Edgerton, 2006

function calc_syn_integ(gmax, tau1, tau2)
    float gmax, tau1, tau2
    float pktime = ({log {tau1}}-{log {tau2}})*{tau1}*{tau2}/({tau1}-{tau2})
    float pkval = ({gmax} / ({tau1} - {tau2}))    \
        * ({exp {-{pktime} / {tau1}}} - {exp {-{pktime} / {tau2}}})
    float A = gmax/{abs {pkval}}
    // Now have all components of synapse alpha function:
    //    gsyn = ((A * gmax)/(tau1-tau2)) * (exp(-t/tau1) - exp(-t/tau2))

    // Can now integrate alpha function over time. Stop integration when
    //    time reaches 5*tau2, where amplitude < 1% of peak.

    float syninteg = ({A} * {gmax}) / ({tau1} - {tau2})    \
        * (({tau2} * {exp -5}) - ({tau1} * {exp {-5*{tau2}/{tau1}}}) \
        - {tau2} + {tau1})

    return {syninteg}
end
    
// ***************************************************************************
// HELPER FUNCTION setup_ttab(str syntype, str comptname, str tabfile, probR)

/* Create timetable and spikegen objects for a single synapse. Fill the 
    timetable from file {tabfile}, connect messages.

Args:
    1. syntype: type of synapse being connected, such as "STN" or "Striatum"
    2. comptname: name of compartment in which synapse is located
    3. tabfile: name of text file containing timetable data
    4. probR: release probability for timetable (prob_act field)
*/


function setup_ttab(syntype, comptname, tabfile, probR)
    str syntype, comptname, tabfile
    float probR
    str syn_name, this_ttab, this_sgen

    str infostruct = {{syntype} @ "info"}
    if ({probR} == 0)
        echo "WARNING: release probability was set to 0. Changing to 1.0!"
        probR = 1.0
    end

    // determine how many timetables already exist.
    int nsyn = {getfield /{infostruct}/{comptname} num_ttabs}
    // determine how many timetables are supposed to exist.
    int nmax = {getfield /{infostruct}/{comptname} num_syns}
    if (nsyn >= nmax)
        echo "Error. You are trying to add another timetable to the " \
            {syntype} " synapse at " {comptname} ", but the requested number " \
            "of timetables has already been connected."
    else
        nsyn = {nsyn} + 1
        this_ttab = {"ttab" @ {nsyn}}
        this_sgen = {"sgen" @ {nsyn}}
        setfield /{infostruct}/{comptname} num_ttabs {nsyn}

        // set up timetable
        create timetable /{infostruct}/{comptname}/{this_ttab}
        setfield /{infostruct}/{comptname}/{this_ttab} \
            maxtime {rundur} act_val 1.0 method 4 fname {tabfile}
        if ({exists /{infostruct}/{comptname}/{this_ttab} prob_act} == 1)
            setfield /{infostruct}/{comptname}/{this_ttab} prob_act {probR}
        else
            echo "WARNING: timetable object does not have prob_act field."
            echo "Check genesis version."
        end

        call /{infostruct}/{comptname}/{this_ttab} TABFILL    

        // set up spikegen
        create spikegen /{infostruct}/{comptname}/{this_sgen}
        setfield /{infostruct}/{comptname}/{this_sgen} output_amp 1 thresh 0.5

        // pass messages only if timetable was successfully filled.
        if ({getfield /{infostruct}/{comptname}/{this_ttab} allocated} == 1)
            syn_name = {getfield /{infostruct}/{comptname} synname}
            addmsg /{infostruct}/{comptname}/{this_ttab}     \
                /{infostruct}/{comptname}/{this_sgen} INPUT activation
            addmsg /{infostruct}/{comptname}/{this_sgen} \
                   {cellpath}/{comptname}/{syn_name} SPIKE
        else
            // this occurs any time the synaptic rate is 0, or if the tabfile 
            // doesn't exist or is not found. It will NOT crash the simulation.
            echo "Warning: timetable for " {syntype} "  synapse at " \
                 {comptname} " has failed allocation. " \
                "This synapse will not be active."
        end
    end
end


// ***************************************************************************
// HELPER FUNCTION setup_ttab_nofile(str syntype, str comptname, float synrate)
/*
    Create timetable and spikegen objects for a single synapse. Fill the
    timetable internally using the rate parameter synrate. Connect the
    objects appropriately.

Args:
    1. syntype: type of synapse being connected, such as "STN" or "Striatum"
    2. comptname: name of compartment in which synapse is located
    3. synrate: average activity rate (Hz) for this synapse
*/

function setup_ttab_nofile(syntype, comptname, synrate)
    str syntype, comptname
    float synrate
    str syn_name, this_ttab, this_sgen

    str infostruct = {{syntype} @ "info"}
    
    // determine how many timetables already exist.
    int nsyn = {getfield /{infostruct}/{comptname} num_ttabs}
    // determine how many timetables are supposed to exist.
    int nmax = {getfield /{infostruct}/{comptname} num_syns}
    if (nsyn >= nmax)
        echo "Error. You are trying to add another timetable to the " \
            {syntype} " synapse at " {comptname} ", but the requested number " \
            "of timetables has already been connected."
    else
        nsyn = {nsyn} + 1
        this_ttab = {"ttab" @ {nsyn}}
        this_sgen = {"sgen" @ {nsyn}}
        setfield /{infostruct}/{comptname} num_ttabs {nsyn}

        // set up timetable
        create timetable /{infostruct}/{comptname}/{this_ttab}
        if ({synrate} > 0)
            setfield /{infostruct}/{comptname}/{this_ttab}     \
                maxtime {rundur} act_val 1.0 method 2    \
                meth_desc1 {1/{synrate}} meth_desc2 0.0 meth_desc3 3

            call /{infostruct}/{comptname}/{this_ttab} TABFILL    
        end

        // set up spikegen
        create spikegen /{infostruct}/{comptname}/{this_sgen}
        setfield /{infostruct}/{comptname}/{this_sgen} output_amp 1 thresh 0.5

        // pass messages only if timetable was successfully filled.
        if ({getfield /{infostruct}/{comptname}/{this_ttab} allocated} == 1)
            syn_name = {getfield /{infostruct}/{comptname} synname}
            addmsg /{infostruct}/{comptname}/{this_ttab}     \
                /{infostruct}/{comptname}/{this_sgen} INPUT activation
            addmsg /{infostruct}/{comptname}/{this_sgen} \
                   {cellpath}/{comptname}/{syn_name} SPIKE
        else
            // this occurs any time the synaptic rate is 0, or if the tabfile 
            // doesn't exist or is not found. It will NOT crash the simulation.
            echo "Warning: timetable for " {syntype} "  synapse at " \
                 {comptname} " has failed allocation. " \
                "This synapse will not be active."
        end
    end
end


// ***************************************************************************
// HELPER FUNCTION copy_ttab_nofile(str syntype, str comptname, str libobj)
/*
    Copy a template timetable object, create a spikegen object. Connect the
    objects to a synchan.

Args:
    1. syntype: type of synapse being connected, such as "STN" or "Striatum"
    2. comptname: name of compartment in which synapse is located
    3. libobj: name of library timetable object to copy
*/

function copy_ttab_nofile(syntype, comptname, libobj)
    str syntype, comptname, libobj
    str syn_name, this_ttab, this_sgen

    str infostruct = {{syntype} @ "info"}
    
    // determine how many timetables already exist.
    int nsyn = {getfield /{infostruct}/{comptname} num_ttabs}
    // determine how many timetables are supposed to exist.
    int nmax = {getfield /{infostruct}/{comptname} num_syns}
    if (nsyn >= nmax)
        echo "Error. You are trying to add another timetable to the " \
            {syntype} " synapse at " {comptname} ", but the requested number " \
            "of timetables has already been connected."
    else
        nsyn = {nsyn} + 1
        this_ttab = {"ttab" @ {nsyn}}
        this_sgen = {"sgen" @ {nsyn}}
        setfield /{infostruct}/{comptname} num_ttabs {nsyn}
        echo "Compartment " {comptname} " now has " {nsyn} " timetables " \
                "connected to synapse " {syn_name}

        // set up timetable
        copy /library/{libobj} /{infostruct}/{comptname}/{this_ttab}

        // set up spikegen
        create spikegen /{infostruct}/{comptname}/{this_sgen}
        setfield /{infostruct}/{comptname}/{this_sgen} output_amp 1 thresh 0.5

        // pass messages only if timetable was successfully filled.
        if ({getfield /{infostruct}/{comptname}/{this_ttab} allocated} == 1)
            syn_name = {getfield /{infostruct}/{comptname} synname}
            addmsg /{infostruct}/{comptname}/{this_ttab}     \
                /{infostruct}/{comptname}/{this_sgen} INPUT activation
            addmsg /{infostruct}/{comptname}/{this_sgen} \
                   {cellpath}/{comptname}/{syn_name} SPIKE
        else
            // this occurs any time the synaptic rate is 0, or if the tabfile 
            // doesn't exist or is not found. It will NOT crash the simulation.
            echo "Warning: timetable for " {syntype} "  synapse at " \
                 {comptname} " has failed allocation. " \
                "This synapse will not be active."
        end
    end
end



// ***************************************************************************
// ******************************* USER FUNCTIONS ****************************
// ***************************************************************************

//FUNCTION create_syntype_infostruct(str syntype,str comptfile,str wtfile)

/* Read a list of compartments that could potentially receive synapses.
   Create a new neutral element called /{syntype}info, in which there is an 
    entry for each compartment in the list. 
    Each of these elements will be given the following    fields:
        scalefactor: synapse scaling factor
        alloc: 1 = does, 0 = does not have a synapse of type synname.
        synname: name of synaptic conductance (e.g., "AMPA"), initially "none"
 
    At the same time that the compartment names are being read, synaptic weight
    values for those compartments will be read from a separate file ({wtfile}). 
    The weights will be stored in the scalefactor field of the info elements.

    If you just want default scale factors of 1 (e.g. all synapses are the same)
    you can put "none" for the {wtfile} argument.
Input Arguments:
    1. syntype: whatever you want to call this class of inputs
        --> I typically use the presynaptic source ("striatum", "STN", etc.)
    2. comptfile: name of a text file containing compartment names, 1 per line.
    3. wtfile: name of a text file containing synaptic weights, 1 per line.
        --> The ordering of the weight file must match the ordering of the
            compartment file.
*/

function create_syntype_infostruct(syntype, comptfile, wtfile)
    str syntype, comptfile, wtfile
    str comptname
    float synwt

    str infostruct = {{syntype} @ "info"}

    if (! {exists /{infostruct}})
        create neutral /{infostruct}
    end

    // open the ascii text files for reading...
    openfile {comptfile} r
    if ({strcmp {wtfile} "none"} != 0)
        openfile {wtfile} r
        synwt = {readfile {wtfile} -linemode}    // first scale factor from file.
    else
        synwt = 1    // default
    end

    // Get the first compartment name.
    comptname = {readfile {comptfile} -linemode}

    // Loop through the files.
    while (! {eof {comptfile}})

        if ({strcmp {wtfile} "none"} != 0)
            if ({eof {wtfile}})
                echo "Error: not enough scale factors for the number of compts."
                closefile {comptfile}
                closefile {wtfile}
                quit
            end
        end

        // Create a neutral element for this compt, give it the proper fields.
        create neutral /{infostruct}/{comptname}
        addfield /{infostruct}/{comptname} scalefactor
        addfield /{infostruct}/{comptname} num_syns
        addfield /{infostruct}/{comptname} synname
        addfield /{infostruct}/{comptname} num_ttabs
        setfield /{infostruct}/{comptname} scalefactor {synwt} \
            num_syns 0 synname "none" num_ttabs 0

        // Now, get the next compartment name and wt factor.
        comptname = {readfile {comptfile} -linemode}
        if ({strcmp {wtfile} "none"} != 0)
            synwt = {readfile {wtfile} -linemode}
        end
    end
    closefile {comptfile}
    if ({strcmp {wtfile} "none"} != 0)
        if (! {eof {wtfile}})
            echo "Error: number of scaling factors is greater than # compts."
            closefile {wtfile}
            quit
        else
            closefile {wtfile}
        end        
    end
end



// ***************************************************************************
// * FUNCTION add_synchans(str syntype, str fname, str syn_name, str libobj) *

/*
Read a list of compartments from a file. For each compartment, check to see if 
    it already has a synapse named syn_name. If not, copy one from the library.
    To make these synapses active, you must call a separate function to 
    create timetables and connect them.

This function can be called multiple times to add compartment lists from 
    different files. If there is any overlap between the compartment lists, 
    an additional timetable and spikegen will be connected for each entry. 
    So the total number of functional synapses will equal the total number
    of list items read in whether or not they are unique.

Input arguments REQUIRED: 
    1. string with name of synapse type ("striatum", "STN", etc)
    2. string with path & name of file containing the compartment names
    3. string with the name to give these synapses within the compartments
        --> usually you would use "AMPA", but you could separate out your AMPA
            synapses into subgroups this way, like "AMPA_bg" and "AMPA_synch" 
            for background and synchronous synapses, respectively.
    4. string variable with the name of the library synapse object to be
        copied into this compartment. e.g.: "AMPA", "stdpAMPA", etc.

USAGE: 
include <this script>
str syntype = "STN"
str fname = "mySTNcompartments.txt"
str sname = "AMPA_STN"
str libobj = "AMPA"
add_synchans {syntype} {fname} {sname} {libobj}
*/

function add_synchans(syntype, synfname, syn_name, libobj)
    str syntype, synfname, syn_name, libobj

    str infostruct = {{syntype} @ "info"}

    // open file to list compartment names of excitatory synapses
    //    File MUST NOT have any blank lines at the end, or function will fail.
    openfile {synfname} r
    str comptname = {readfile {synfname} -linemode}

    int counter = 0;
    while (! {eof {synfname}})
        if (! {exists /{infostruct}/{comptname}})
            echo "Error: " {comptname} " not found in /" {infostruct}
            closefile {synfname}
            quit
        end
        if ({getfield /{infostruct}/{comptname} num_syns} == 0)
            // Copy a synapse from the library to the compartment    
            copy /library/{libobj} {cellpath}/{comptname}/{syn_name}
            addmsg {cellpath}/{comptname}/{syn_name}    \
                     {cellpath}/{comptname} CHANNEL Gk Ek
            addmsg {cellpath}/{comptname} \
                     {cellpath}/{comptname}/{syn_name} VOLTAGE Vm
            if ({isa stdpSynchan /library/{libobj}})
                addmsg {cellpath}/soma {cellpath}/{comptname}/{syn_name} \
                    VOLTAGE Vm
                setfield {cellpath}/{comptname}/{syn_name} Vspkmsg_idx \
                    {Vspkmsg_stdp}
            end
            // Register the synapse in /{infostruct}
            setfield /{infostruct}/{comptname} synname {syn_name}
            counter = counter + 1
        end
        // Increment num_syns in infostruct
        setfield /{infostruct}/{comptname} num_syns \
            {{getfield /{infostruct}/{comptname} num_syns} + 1}
        // Get next compartment name from file
        comptname = {readfile {synfname} -linemode}
    end
    closefile {synfname}
    return {counter}
end


// ***************************************************************************
// * FUNCTION add_synchans_combofile(str syntype, str fname, str syn_name, str libobj) *

/*
Read a combined compartment names & numbers list (each line has first the
    compartment name, then the # of synapses to go in that compartment).
    Copy the appropriate library synchan object to the compartment, set the
    fields in /{infostruct}/{comptname} to enable timetable setup.
    --> This function does NOT set up or connect timetables. That must be
        handled separately.

Input arguments REQUIRED: 
    1. string with name of synapse type ("striatum", "STN", etc)
    2. string with path & name of file containing the compartment names & #s
    3. string with the name to give these synapses within the compartments
        --> usually you would use "AMPA", but you could separate out your AMPA
            synapses into subgroups this way, like "AMPA_bg" and "AMPA_synch" 
            for background and synchronous synapses, respectively.
    4. string variable with the name of the library synapse object to be
        copied into this compartment. e.g.: "AMPA", "stdpAMPA", etc.

USAGE: 
include <this script>
str syntype = "STN"
str fname = "mySTNcompartments.txt"
str sname = "AMPA_STN"
str libobj = "AMPA"
add_synchans {syntype} {fname} {sname} {libobj}
*/

function add_synchans_combofile(syntype, synfname, syn_name, libobj)
    str syntype, synfname, syn_name, libobj

    str infostruct = {{syntype} @ "info"}

    // open file to list compartment names and numbers
    //    File MUST NOT have any blank lines at the end, or function will fail.
    openfile {synfname} r
    str thisline = {readfile {synfname} -linemode}

    // parse the line into comptname and #syns
    str comptname = {getarg {arglist {thisline}} -arg 1}
    float nsyns = {getarg {arglist {thisline}} -arg 2}

    int counter = 0;
    while (! {eof {synfname}})
        if (! {exists /{infostruct}/{comptname}})
            echo "Error: " {comptname} " not found in /" {infostruct}
            closefile {synfname}
            quit
        end
        if ({getfield /{infostruct}/{comptname} num_syns} != 0)
            echo "Error: " {comptname} " already has synapse of this type.\n"
            closefile {synfname}
            quit
        else
            // Copy a synapse from the library to the compartment    
            copy /library/{libobj} {cellpath}/{comptname}/{syn_name}
            addmsg {cellpath}/{comptname}/{syn_name}    \
                     {cellpath}/{comptname} CHANNEL Gk Ek
            addmsg {cellpath}/{comptname} \
                     {cellpath}/{comptname}/{syn_name} VOLTAGE Vm
            if ({isa stdpSynchan /library/{libobj}})
                addmsg {cellpath}/soma {cellpath}/{comptname}/{syn_name} \
                    VOLTAGE Vm
                setfield {cellpath}/{comptname}/{syn_name} Vspkmsg_idx \
                    {Vspkmsg_stdp}
            end
            // Register the synapse in /{infostruct}
            setfield /{infostruct}/{comptname} synname {syn_name}

            // Set the num_syns field
            setfield /{infostruct}/{comptname} num_syns {nsyns}

            counter = counter + 1
        end
        // Get next compartment name & #syns from file
        thisline = {readfile {synfname} -linemode}
        if (! {eof {synfname}})
            comptname = {getarg {arglist {thisline}} -arg 1}
            nsyns = {getarg {arglist {thisline}} -arg 2}
        end
    end
    closefile {synfname}
    return {counter}
end



// ***************************************************************************
// FUNCTION pad_synchan_list(str syntype, str fname, str syn_name, str libobj, int num_syns)

/*Determine how many synapses of type syntype have already been added, then 
    add additional synapses to compartments listed in {fname} until the total 
    number of synapses = {num_syns}

Input arguments REQUIRED: 
    1. string variable with syntype ("striatum", "STN", etc.)
    2. path & name of file containing the compartment names
    3. string variable with the name to give this group of synchans
        --> e.g. "AMPA_stn", "AMPA_background", etc.
    4. string with name of synchan object to copy from library
    5. integer: total number of synapses desired.
        --> The number added here will be (total - pre-existing)

USAGE: 
include <this script>
str syntype = "STN"
str fname = "myBackgroundSTNlist.txt"
str sname = "AMPA_background"
str libobj = "AMPA"
int num_syns = 100
pad_STN_synlist {syntype} {fname} {sname} {libobj} {num_syns}
*/

function pad_synchan_list(syntype, fname, syn_name, libobj, num_syns)
    str syntype, fname, syn_name, libobj
    int num_syns

    str elname
    str infostruct = {{syntype} @ "info"}

    int syn_count = 0

    foreach elname ({el /{infostruct}/##[OBJECT=neutral]})
        syn_count = {syn_count} + {getfield {elname} num_syns}
    end

    if ({syn_count} > {num_syns})
        echo "Error: " {num_syns} " synapses were requested, but " {syn_count} \
            " synapses already exist."
        quit
    else
        echo "Number of synapses: " {syn_count}
    end

    echo "Opening file: " {fname}    
    openfile {fname} r
    str comptname = {readfile {fname} -linemode}

    while ({syn_count} < {num_syns})
//        echo "syn_count: " {syn_count} ", num_syns: " {num_syns}
        if ({eof {fname}})
            echo "Error: not enough compartments in list."
            closefile {fname}
            quit
        end
        if ({getfield /{infostruct}/{comptname} num_syns} == 0)
            // Copy a synapse from the library to the compartment    
            echo "Adding " {syn_name} " synapse to compartment: " {comptname}
            copy /library/{libobj} {cellpath}/{comptname}/{syn_name}
            addmsg {cellpath}/{comptname}/{syn_name}    \
                     {cellpath}/{comptname} CHANNEL Gk Ek
            addmsg {cellpath}/{comptname} \
                     {cellpath}/{comptname}/{syn_name} VOLTAGE Vm
            if ({isa stdpSynchan /library/{libobj}})
                addmsg {cellpath}/soma {cellpath}/{comptname}/{syn_name} \
                    VOLTAGE Vm
                setfield {cellpath}/{comptname}/{syn_name} Vspkmsg_idx \
                    {Vspkmsg_stdp}
            end
            // Register the synapse in /{infostruct} and iterate counters
            setfield /{infostruct}/{comptname} synname {syn_name}
        end
        setfield /{infostruct}/{comptname} num_syns \
            {getfield /{infostruct}/{comptname} num_syns} + 1
        syn_count = {syn_count} + 1
        comptname = {readfile {fname} -linemode}
    end
    echo "Total number of " {syntype} " inputs: " {syn_count}
end


// ***************************************************************************
//************* FUNCTION ampscale_syns(str syntype, float Gmax) **************

/* Scale the gmax value of each synapse according to the weight value for that
    synapse's compartment in infostruct. Normalize the scaling such that the 
    mean unitary gmax for the collection of synapses is equal to the original 
    Gmax. This ensures that two different weight distributions will still 
    result in the same total amount of synaptic conductance being applied 
    to the cell, provided that synaptic rates and the number of synapses are 
    the same for both distributions.
    --> Note that if a synapse represents multiple inputs (has multiple
        timetables driving it), all of the inputs will be scaled the same.

Input arguments REQUIRED: 
    1. syntype
    2. Gmax for these synchans

USAGE: 
include <this script>
str syntype = "STN"
float Gmax = 0.25e-9
scale_syns {syntype} {Gmax}
*/

function ampscale_syns(syntype, Gmax)
    str syntype
    float Gmax

    str elname
    int nsyns
    int syn_count = 0
    float totscale = 0
    float meanscale = 0
    str syn_name, comptname

    str infostruct = {{syntype} @ "info"}
    echo "Setting synapse weights..."
    
    foreach elname ({el /{infostruct}/##[OBJECT=neutral]})
        if ({getfield {elname} num_syns} > 0)
            nsyns = {getfield {elname} num_syns}
            syn_count = {syn_count} + {nsyns}
            totscale = {totscale} + ({getfield {elname} scalefactor}*{nsyns})
        end
    end
    if ({syn_count} == 0)
        echo "No synapses of type " {syntype} " allocated."
        quit
    else
        meanscale = {{totscale} / {syn_count}}
        echo "Number of " {syntype} " syns: " {syn_count}
        echo "Sum total of all scaling factors: "    {totscale} 
        echo "Mean scaling factor: " {meanscale}
        foreach elname ({el /{infostruct}/##[OBJECT=neutral]})
            if ({getfield {elname} num_syns} > 0)
                syn_name = {getfield {elname} synname}
                // get the compartment name without the preceding /{infostruct}/ part.
                comptname = {strsub {elname} {"/" @ {infostruct} @ "/"} ""}
                setfield {cellpath}/{comptname}/{syn_name} gmax        \ 
                    {{Gmax} * {getfield {elname} scalefactor} / {meanscale}}
                echo "synapse " {syn_name} " at " {comptname}    \
                    " has gmax " {getfield {cellpath}/{comptname}/{syn_name} gmax}
            end
        end
    end
end        


// ***************************************************************************
// ***************** FUNCTION scale_synweights(str syntype) *******************

/* Set the synapse.weight value of each synapse equal to the weight value
    in infostruct. Do not normalize the scaling. This is used to initialize
    synapses to the state they were in following a plasticity run such as
    STDP.

Input arguments REQUIRED: 
    1. syntype

USAGE: 
include <this script>
str syntype = "STN"
scale_synweights {syntype}
*/

function scale_synweights(syntype)
    str syntype

    str elname
    int nsyns, i
    str syn_name, comptname

    str infostruct = {{syntype} @ "info"}
    echo "Setting synapse weights..."
    
    foreach elname ({el /{infostruct}/##[OBJECT=neutral]})
        echo {elname}
        if ({getfield {elname} num_syns} > 0)
            syn_name = {getfield {elname} synname}
            // get the compt name without the preceding /{infostruct}/ part.
            comptname = {strsub {elname} {"/" @ {infostruct} @ "/"} ""}
            nsyns = {getfield {cellpath}/{comptname}/{syn_name} nsynapses}
            if ({nsyns} < {getfield {elname} num_syns})
                echo "Error. scale_synweights must be called AFTER the " \
                    "timetables have been connected, or the synapse weights " \
                    "will not be scaled correctly!"
            end
            for (i=0; i<{nsyns}; i=i+1)
                setfield {cellpath}/{comptname}/{syn_name} \
                    synapse[{i}].weight {getfield {elname} scalefactor}
                echo "synapse " {syn_name} " number " {i} " at " {comptname} \
                 " now has weight " \
                {getfield {cellpath}/{comptname}/{syn_name} synapse[{i}].weight}
            end
        end
    end
end        


// ***************************************************************************
// FUNCTION read_synweights_fromfile(str syn_name, str wtfile, str comptfile, str cellpath)

/* Read synapse weights from an ascii text file, go through the compartments
    listed in a second text file and set each one's weight to the value in the
    file. Do not normalize the scaling. This is used to initialize
    synapses to the state they were in following a plasticity run such as
    STDP.

    *** THIS WORKS ONLY WHERE THE NUMBER OF TIMETABLES PER SYNAPSE = 1! ***

Input arguments REQUIRED: 
    1. syn_name: name of synchan objects to be set, e.g. "AMPA"
    2. wtfile: name of file from which weights will be read.
    3. comptfile: name of file from which compartment names will be read.
    --> obviously the order of the compartment names needs to match the
            order of the synapse weights.
    4. cellpath: path to cell root element (without trailing forward slash)

USAGE: 
include <this script>
str syn_name = "AMPA"
str wtfile = "./mysynweights.asc"
str comptfile = "./mycomptslist.asc"
str cellpath = "/mycell"
read_synweights_fromfile {syn_name} {wtfile} {comptfile} {cellpath}
*/

function read_synweights_fromfile(syn_name, wtfile, comptfile, cellpath)
    str syn_name, wtfile, comptfile, cellpath

    int nsyns, i
    str comptname, elname
    float synwt

    echo "Setting synapse weights..."
    
    // open the ascii text files for reading...
    openfile {comptfile} r
    openfile {wtfile} r

    // Get the first compartment name & synapse weight
    comptname = {readfile {comptfile} -linemode}
    synwt = {readfile {wtfile} -linemode}

    // Loop through the files.
    while (! {eof {comptfile}})

        if ({eof {wtfile}})
            echo "Error: not enough scale factors for the number of compts."
            closefile {comptfile}
            closefile {wtfile}
            quit
        end
        
        nsyns = {getfield {cellpath}/{comptname}/{syn_name} nsynapses}
        for (i=0; i<{nsyns}; i=i+1)
            setfield {cellpath}/{comptname}/{syn_name} \
                synapse[{i}].weight {synwt}
        end
        echo "synapse " {syn_name} " at " {comptname} " has weight " \
             {getfield {cellpath}/{comptname}/{syn_name} synapse[0].weight}

        // Now, get the next compartment name and wt factor.
        comptname = {readfile {comptfile} -linemode}
        synwt = {readfile {wtfile} -linemode}
    end

    closefile {comptfile}
    if (! {eof {wtfile}})
        echo "Error: number of weight factors is greater than # compts."
        closefile {wtfile}
        quit
    else
        closefile {wtfile}
    end        
end
    
// ***************************************************************************
// FUNCTION read_synapse_timetables(str syntype, str comptfile, str ttab_fbase, str ttab_idx_fname, float syn_probR)

/*
Read a list of compartments from {comptfile}. Each of these compartments must
    already have a synapse in it and the synapse must be registered in the 
    information struct for {syntype}.
    A timetable object will be created in /{infostruct}/{comptname}/
    and the table itself will be read in from a file named
    {ttab_fbase} @ {idx}. 

Input Arguments:
    1.    syntype: name for a group of synapses ("striatum", "STN", etc.)
    2.    comptfile: path and name of compartment list.
            e.g. "../../common/GP1/comptlists/gp1_STNinputcomps.asc"
    3.    ttab_fbase: path and filename base for timetable files without the 
            index #s.
            e.g. "../../utilities/timetables/STN/independent/10_HzSTN"
    4.    ttab_idx_fname: path and filename of the timetable indices for this
            compartment list. The first compartment in comptfile would be 
            assigned the timetable with the index number first found in 
            ttab_idx_fname.
            If there are 2 numbers per line in this file, the first is a group
            number and the second a synapse number (for simulations involving
            multiple synchronous groups of inputs).
    5.    syn_probR: release probability to apply to timetables.

    For example, if the first compartment is 'soma', {ttab_fbase} is 
        "../../utilities/timetables/STN/independent/10_HzSTN", and the first 
        row of {ttab_idx_fname} is 25, then the STN synapse in the soma would
        get the timetable read from 
        "../../utilities/timetables/STN/independent/10_HzSTN_25.asc"

This function can be called multiple times to add compartment lists from 
    different files. If a compartment name appears more than once,
    multiple timetables will be connected to the synchan for that compartment.

USAGE: 
include <this script>
str syntype = "STN"
str comptfile = "mySTNcompts.txt"
str ttab_fbase = "../../utilities/timetables/STN/independent/10_HzSTN"
str ttab_idx_fname = "../../common/GP1/ttab_idxs/ttabidx_STN_indep.asc)"
read_synapse_timetables {syntype} {comptfile} {ttab_fbase} {ttab_idx_fname}
*/

function read_synapse_timetables(syntype, comptfile, ttab_fbase, ttab_idx_fname, syn_probR)
    str syntype, comptfile, ttab_fbase, ttab_idx_fname
    float syn_probR

    str comptname, thisline, tabfile, syn_name, basename
    int groupidx, synidx, dset

    echo "Opening compartment list file " {comptfile}
    echo "Opening timetable idx file " {ttab_idx_fname}
        
    openfile {comptfile} r    
    openfile {ttab_idx_fname} r
    
    // get first compartment name
    comptname = {readfile {comptfile} -linemode}

    // get index number(s) for first timetable
    thisline = {readfile {ttab_idx_fname} -linemode}

    // determine how many index numbers were in the line
    int narg = 0
    foreach tstr ({arglist {thisline}})
        // count the number of arguments per line
        narg = narg + 1;
    end

    // parse the line into groupidx and (if applicable) synidx
    if ({narg} == 3)
        dset = {getarg {arglist {thisline}} -arg 1}
        groupidx = {getarg {arglist {thisline}} -arg 2}
        synidx = {getarg {arglist {thisline}} -arg 3}
        basename = "_dset_" @ {dset} @ "_ctxt_" @ {groupidx} @ \ 
                        "_idx_" @ {synidx} @ ".asc"
    elif ({narg} == 2)
        groupidx = {getarg {arglist {thisline}} -arg 1}
        synidx = {getarg {arglist {thisline}} -arg 2}
        basename = "_groupidx_" @ {groupidx} @ "_synidx_" @ {synidx} @ ".asc"

    elif ({narg} == 1)
        groupidx = {getarg {arglist {thisline}} -arg 1}
        synidx = 0
        basename = "_" @ {groupidx} @ ".asc"
    else
        echo "Error: " {ttab_idx_fname} " should have 1 or 2 arguments per line."
    end

    /* Cycle through the list of compartments, create a timetable and spikegen
        for each, fill the tables, pass messages. */
    while (! {eof {comptfile}})
        if ({eof {ttab_idx_fname}})
            echo "Error: not enough timetable index rows for the # of compartments"
            closefile {comptfile}
            closefile {ttab_idx_fname}
            quit
        end

        // Concatenate strings to form complete timetable file name
        tabfile = {ttab_fbase} @ {basename}
        echo "timetable for synapse at " {comptname} " read from: "
        echo "   " {tabfile}

        // call helper function to create timetable & spikegen
        setup_ttab {syntype} {comptname} {tabfile} {syn_probR}

        // get next compartment name and index numbers
        comptname = {readfile {comptfile} -linemode}

        thisline = {readfile {ttab_idx_fname} -linemode}

        if (!{eof {ttab_idx_fname}})
            if ({narg} == 3)
                dset = {getarg {arglist {thisline}} -arg 1}
                groupidx = {getarg {arglist {thisline}} -arg 2}
                synidx = {getarg {arglist {thisline}} -arg 3}
                basename = "_dset_" @ {dset} @ "_ctxt_" @ {groupidx} @ \ 
                                "_idx_" @ {synidx} @ ".asc"
            elif ({narg} == 2)
                groupidx = {getarg {arglist {thisline}} -arg 1}
                synidx = {getarg {arglist {thisline}} -arg 2}
                basename = "_groupidx_" @ {groupidx} @ "_synidx_" @ {synidx} @ ".asc"
            else
                groupidx = {getarg {arglist {thisline}} -arg 1}
                synidx = 0
                basename = "_" @ {groupidx} @ ".asc"
            end
        end
    end
end


// ***************************************************************************
// FUNCTION pad_timetables_fromfiles(str syntype,str ttab_fbase,str ttab_idx_fname, float syn_probR)

/*
Find all synapses that are registered in /{infostruct} but for which there is no
    timetable and spikegen. Create a timetable and spikegen in the same way 
    that read_synapse_timetables would do.

Input Arguments:
    1. syntype
    2.    ttab_fbase: path and filename base for timetable files without the index #s.
            e.g. "../../utilities/timetables/STN/independent/10_HzSTN"
    3.    ttab_idx_fname: path and filename of the timetable indices for this
            compartment list. The first compartment in comptfile would be 
            assigned the timetable with the index number first found in 
            ttab_idx_fname.
            If there are 2 numbers per line in this file, the first is a group
            number and the second a synapse number (for simulations involving
            multiple synchronous groups of inputs).
    4.    startidx: line number in ttabidx file to start at.
    5.    syn_probR: release probability for timetables.
*/

function pad_timetables_fromfiles(syntype, ttab_fbase, ttab_idx_fname, startidx, syn_probR)
    str syntype, ttab_fbase, ttab_idx_fname
    int startidx
    float syn_probR

    if ({startidx} == 0)
        echo "pad_timetables_fromfiles WARNING:"
        echo "Starting line number for ttab_idx file reads is 0."
        echo "Changing to 1."
        startidx = 1
    end

    if ({syn_probR} == 0)
        echo "pad_timetables_fromfiles WARNING:"
        echo "Synapse release probability is set to 0!"
    end

    str comptname, thisline, tabfile, syn_name, basename, elname
    int groupidx, synidx, dset, i, nsyns, nttabs
    
    str infostruct = {{syntype} @ "info"}

    echo "Opening timetable idx file " {ttab_idx_fname}
        
    openfile {ttab_idx_fname} r

    // jump to starting row
    for (i=1; i<={startidx}; i=i+1)    
        // get index number(s) for first timetable
        thisline = {readfile {ttab_idx_fname} -linemode}
    end

    // determine how many index numbers were in the line
    int narg = 0
    foreach tstr ({arglist {thisline}})
        // count the number of arguments per line
        narg = narg + 1;
    end
    echo "Number of args per line in ttab_idx file: " {narg}

    /* Cycle through the compartments, create a timetable and spikegen for 
        each, fill the tables, pass messages. */
    foreach elname ({el /{infostruct}/##[OBJECT=neutral]})
        // get the compartment name without the preceding /{infostruct}/ part.
        comptname = {strsub {elname} {"/" @ {infostruct} @ "/"} ""}

        // determine if timetables are needed.
        nsyns = {getfield {elname} num_syns}
        nttabs = {getfield {elname} num_ttabs}

        // create & connect the necessary number of new timetables & spkgens
        while ({nttabs} < {nsyns})
            // Make sure {thisline} is valid
            if ({eof {ttab_idx_fname}})
                echo "Error: not enough ttab index rows for the # of compts"
                closefile {ttab_idx_fname}
                quit
            end

            // parse {thisline} into groupidx and (if applicable) synidx
            if ({narg} == 3)
                dset = {getarg {arglist {thisline}} -arg 1}
                groupidx = {getarg {arglist {thisline}} -arg 2}
                synidx = {getarg {arglist {thisline}} -arg 3}
                basename = "_dset_" @ {dset} @ "_ctxt_" @ {groupidx} @ \ 
                                "_idx_" @ {synidx} @ ".asc"

            elif ({narg} == 2)
                groupidx = {getarg {arglist {thisline}} -arg 1}
                synidx = {getarg {arglist {thisline}} -arg 2}
                basename= "_groupidx_" @ {groupidx} @ "_synidx_" @ {synidx} @ ".asc"
            else
                groupidx = {getarg {arglist {thisline}} -arg 1}
                synidx = 0
                basename = "_" @ {groupidx} @ ".asc"
            end

            // Concatenate strings to form complete timetable file name
            tabfile = {ttab_fbase} @ {basename}
            echo "timetable for synapse at " {comptname} " read from: "
            echo "        " {tabfile}

            // call helper function to create timetable & spikegen
            setup_ttab {syntype} {comptname} {tabfile} {syn_probR}

            // increment counter
            nttabs = {nttabs} + 1

            // get index number(s) for next timetable
            thisline = {readfile {ttab_idx_fname} -linemode}    
        end
    end
    closefile {ttab_idx_fname}
end


// ***************************************************************************
// ******** FUNCTION pad_timetables_nofile(str syntype, float synrate) ********

/* 
Scan through all synapses in /{infostruct}, find those that need a 
    timetable and spikegen, create the objects, fill the timetable using the
    rate parameter, and connect the objects to the synapse.

Input Arguments:
    1. syntype: name of synapse to search for (e.g. "striatum" or "STN")
    2. synrate: mean activation rate for each synapse (in Hz)

    /* Cycle through the compartments, create a timetable and spikegen for 
        each provided they don't already exist, fill the tables, pass messages. */
function pad_timetables_nofile(syntype, synrate)
    str syntype
    float synrate

    str infostruct = {{syntype} @ "info"}
    str elname, comptname
    int nsyns, nttabs

    foreach elname ({el /{infostruct}/##[OBJECT=neutral]})
        // get the compt name without the preceding /{infostruct}/ part.
        comptname = {strsub {elname} {"/" @ {infostruct} @ "/"} ""}

        // determine if timetables are needed.
        nsyns = {getfield {elname} num_syns}
        nttabs = {getfield {elname} num_ttabs}

        // create & connect the necessary number of new timetables & spkgens
        while ({nttabs} < {nsyns})
            // call helper function to create timetable & spikegen
            setup_ttab_nofile {syntype} {comptname} {synrate}
            echo "New timetable added to " {syntype} " synapse at " {comptname}
            nttabs = {nttabs} + 1
        end
    end
end

// ***************************************************************************
// ** FUNCTION pad_timetables_nofile_multisyns(str syntype, float synrate) ***

/* 
Scan through all synapses in /{infostruct}, find those that need a 
    timetable and spikegen, create the objects, fill the timetable using the
    rate parameter, and connect the objects to the synapse.

Input Arguments:
    1. syntype: name of synapse to search for (e.g. "striatum" or "STN")
    2. synrate: mean activation rate for each synapse (in Hz)

    /* Cycle through the compartments, create a timetable and spikegen for 
        each provided they don't already exist, fill the tables, pass messages. */
function pad_timetables_nofile(syntype, synrate)
    str syntype
    float synrate

    str infostruct = {{syntype} @ "info"}
    str elname, comptname
    int nsyns, nttabs

    foreach elname ({el /{infostruct}/##[OBJECT=neutral]})
        // get the compt name without the preceding /{infostruct}/ part.
        comptname = {strsub {elname} {"/" @ {infostruct} @ "/"} ""}

        // determine if timetables are needed.
        nsyns = {getfield {elname} num_syns}
        nttabs = {getfield {elname} num_ttabs}

        // create & connect the necessary number of new timetables & spkgens
        while ({nttabs} < {nsyns})
            // call helper function to create timetable & spikegen
            setup_ttab_nofile {syntype} {comptname} {synrate}
            echo "New timetable added to " {syntype} " synapse at " {comptname}
            nttabs = {nttabs} + 1
        end
    end
end

// ***************************************************************************
// FUNCTION pad_timetables_nofile_synch(syntype, synrate, idx)

/* 
Scan through all synapses in /{infostruct}, find those that need a 
    timetable and spikegen. Create a SINGLE template timetable and fill its
    table using the synrate parameter. All of the synapses will share this
    common timetable, so they will be synchronous. For each needy synapse,
    copy the template timetable, create a spikegen, connect the objects.

Input Arguments:
    1. syntype: name of synapse to search for (e.g. "striatum" or "STN")
    2. synrate: mean activation rate for each synapse (in Hz)
    3. idx: index number give template ttab, in case there are multiple of
            these.
*/

function pad_timetables_nofile_synch(syntype, synrate, idx)
    str syntype
    float synrate
    int idx, nsyns, nttabs

    str infostruct = {{syntype} @ "info"}
    str elname, comptname

    str libobj = {{syntype} @ "_ttab_" @ {idx}}
    // set up template timetable in library
    create timetable /library/{libobj}
    if ({synrate} > 0)
        setfield /library/{libobj}     \
            maxtime {rundur} act_val 1.0 method 2    \
            meth_desc1 {1/{synrate}} meth_desc2 0.0 meth_desc3 3

        call /library/{libobj} TABFILL    
    end
    
    foreach elname ({el /{infostruct}/##[OBJECT=neutral]})
        // get the compt name without the preceding /{infostruct}/ part.
        comptname = {strsub {elname} {"/" @ {infostruct} @ "/"} ""}

        // determine if timetables are needed.
        nsyns = {getfield {elname} num_syns}
        nttabs = {getfield {elname} num_ttabs}

        // create & connect the necessary number of new timetables & spkgens
        while ({nttabs} < {nsyns})
            // call helper function to create timetable & spikegen
            copy_ttab_nofile {syntype} {comptname} {libobj}
            echo "Library timetable copied to synapse at " {comptname}
            nttabs = {nttabs} + 1
        end
    end
end


// ***************************************************************************
// FUNCTION pad_timetables_ratescale(str syntype, float synrate, float scl)

/* 
For each compartment receiving an input, determine the ratio of that compt's
    size to the mean size of the whole group of compartments.
    Configure the timetable to use input rate = {synrate} * {size_ratio}
    
Scan through all synapses in /{infostruct}, find those that need a 
    timetable and spikegen, create the objects, fill the timetable using the
    rate parameter, and connect the objects to the synapse.

Input Arguments:
    1. syntype: name of synapse to search for (e.g. "striatum" or "STN")
    2. synrate: mean activation rate for each synapse (in Hz)
    3. scl: rate scaling strategy selector: 
        --if 2, normalize by compartment length
        --if 3, multiply by the num_syns field in /{infostruct}/{comptname}
        --otherwise, normalize by compartment surface area (default)

    /* Cycle through the compartments, create a timetable and spikegen for 
        each provided they don't already exist, fill the tables, pass messages. */
function pad_timetables_ratescale(syntype, synrate, scl)
    str syntype
    float synrate, scl

    str infostruct = {{syntype} @ "info"}
    str elname, comptname
    float d, l, surf
    float totsize, meansize, thisrate, size_ratio
    int num_compts, nsyns, nttabs

    if ({scl} != 3)
        totsize = 0.0
        num_compts = 0
        // cycle through input compartments, determine mean size
        foreach elname ({el /{infostruct}/##[OBJECT=neutral]})
            addfield {elname} surfarea
            addfield {elname} len
            // get the compt name without the preceding /{infostruct}/ part.
            comptname = {strsub {elname} {"/" @ {infostruct} @ "/"} ""}
            //echo {comptname}
            d = {getfield {cellpath}/{comptname} dia}
            if ({strcmp {comptname} "soma"} == 0)
                l = d;
            else
                l = {getfield {cellpath}/{comptname} len}
            end
            surf = {PI}*{l}*{d}
            if ({scl} == 2)
                totsize = {totsize} + {l}
            else
                totsize = {totsize} + {surf}
            end
            num_compts = {num_compts} + 1
            setfield {elname} surfarea {surf}
            setfield {elname} len {l}
        end

        meansize = {totsize} / {num_compts}
        if ({scl} == 2)
            echo "Normalizing by compartment length..."
            echo "Total length (microns): " {{totsize}*1e6}
            echo "Mean length (microns): " {{meansize}*1e6}
        else
            echo "Normalizing by compartment surface area..."
            echo "Total input surface area (microns2): " {{totsize}*1e12}
            echo "Mean S.A. of input compts (microns2): " {{meansize}*1e12}
        end
        echo "Total number of " {syntype} " input events per second: " \
            {{synrate}*{num_compts}}
    end

    foreach elname ({el /{infostruct}/##[OBJECT=neutral]})
        //echo {elname}
        if ({scl} == 2)
            size_ratio = {getfield {elname} len}/{meansize}
        elif ({scl} == 3)
            size_ratio = {getfield {elname} num_syns}
        else
            size_ratio = {getfield {elname} surfarea}/{meansize}
        end
        thisrate = {{synrate}*{size_ratio}}
        // get the compt name without the preceding /{infostruct}/ part.
        comptname = {strsub {elname} {"/" @ {infostruct} @ "/"} ""}
        //echo {comptname}
        echo "Compartment " {comptname} " receives " {thisrate} \
            " " {syntype} " input events per second." 

        if ({scl} == 3)
            nsyns = 1
            nttabs = 0
        else
            // determine how many timetables are needed.
            nsyns = {getfield {elname} num_syns}
            nttabs = {getfield {elname} num_ttabs}
        end

        // create & connect the necessary number of new timetables & spkgens
        while ({nttabs} < {nsyns})
            // call helper function to create timetable & spikegen
            setup_ttab_nofile {syntype} {comptname} {thisrate}
            echo "Rate scaled timetable added to synapse " \
                {syntype} " at " {comptname}
            nttabs = {nttabs} + 1
        end
    end
end


// ***************************************************************************
// FUNCTION add_syns_const(str syntype, str fname, str syn_name, float syn_rate, float Echan, float Gsyn, float tauRise, float tauFall)

/*
Read a list of compartments from a file. For each one, add a leak
    channel object with reversal potential Echan and with constant conductance
    equal to the average conductance that would be expected given the
    rate, unitary size & time-course of the synapse being replaced.

Input arguments REQUIRED: 
    1. string with synapse type ("STN", "striatum", etc.)
    2. string with path & name of file containing the compartment names
    3. string with the name to give these synapses within the compartments
    4. float with the average activation rate (in Hz) for the synapse being
        replaced
    5. float with the reversal potential (in volts) of the synapse.
    6. float with the unitary Gmax of the synapse being replaced.
    7. float with the rise tau (synchan tau1) of the synapse being replaced.
    8. float with the decay tau (synchan tau2) of the synapse being replaced.

USAGE: 
include <this script>
str syntype = "STN"
str fname = "STNinputcompts.asc"
str sname = "AMPA_const"
float synrate = 10
float Echan = 0.0
float Gmax = 0.25e-09
float t1 = 0.001
float t2 = 0.003

add_syns_const {syntype} {fname} {sname}    \
                         {synrate} {Echan} {Gmax} {t1} {t2}
*/

function add_syns_const(syntype, fname, s_name, syn_rate, Echan, Gsyn, t1, t2)
    str syntype, fname, s_name
    float syn_rate, Echan, Gsyn, t1, t2

    str compt
    float gsyn

    str infostruct = {{syntype} @ "info"}

    // calculate average synaptic conductance for given rate
    gsyn = {syn_rate} * { calc_syn_integ {Gsyn} {t1} {t2} }

    echo "Implementing synaptic conductance as tonic leak..."
    echo "Conductance to be added to each input compt (nS): " {gsyn}

    openfile {fname} r
    compt = {readfile {fname} -linemode}

    while (! {eof {fname}})
        if (! {exists /{infostruct}/{compt}})
            echo "Error: " {compt} " not found in /" {infostruct}
            closefile {fname}
            quit
        end
        if ({getfield /{infostruct}/{compt} alloc} == 0)
            // copy leak channel from library to compartment, set values.
            copy /library/leakchan {cellpath}/{compt}/{s_name}
            setfield {cellpath}/{compt}/{s_name} \
                Gbar {gsyn} Ek {Echan}

            // pass messages
            addmsg {cellpath}/{compt} {cellpath}/{compt}/{s_name} VOLTAGE Vm
            addmsg {cellpath}/{compt}/{s_name} {cellpath}/{compt} CHANNEL Gk Ek    
                
            // diagnostic
            echo "Constant synapse added to compt: " {compt}

            // Register the synapse in /{infostruct}
            setfield /{infostruct}/{compt} alloc 1 synname {s_name}

            // Get next compartment name
            compt = {readfile {fname} -linemode}
        end
    end
    closefile {fname}
end


// ***************************************************************************
// FUNCTION add_syns_const_ratescaled(str syntype, str fname, str syn_name, float syn_rate, float Echan, float Gsyn, float tauRise, float tauFall)

/*
Read a list of compartments from a file. Go through the compartments and
    compute the total surface area of all. Then for each one, add a leak
    channel object with reversal potential Echan and with constant conductance
    equal to the average conductance that would be expected given the synapse
    rate, the compartment's surface area relative to that of the others, and
    the unitary size & time-course of the synapse being replaced.

Input arguments REQUIRED: 
    1. string with synapse type ("STN", "striatum", etc.)
    2. string with path & name of file containing the compartment names
    3. string with the name to give these synapses within the compartments
    4. float with the average activation rate (in Hz) for the synapse being
        replaced
    5. float with the reversal potential (in volts) of the synapse.
    6. float with the unitary Gmax of the synapse being replaced.
    7. float with the rise tau (synchan tau1) of the synapse being replaced.
    8. float with the decay tau (synchan tau2) of the synapse being replaced.

USAGE: 
include <this script>
str syntype = "striatum"
str fname = "myGABAcompartments.txt"
str sname = "GABA_const"
float synrate = 10
float Echan = -0.08
float Gmax = 1e-09
float t1 = 0.003
float t2 = 0.012

add_syns_const_ratescaled {syntype} {fname} {sname}    \
                         {synrate} {Echan} {Gmax} {t1} {t2}
*/

function add_syns_const_ratescaled(syntype, fname, s_name, syn_rate, Echan, Gsyn, t1, t2)
    str syntype, fname, s_name
    float syn_rate, Echan, Gsyn, t1, t2

    int i, num_compts
    str compt
    float d,l,surf
    float thisrate, gsyn, gsyn_uni
    float totsurf, meansurf

    str infostruct = {{syntype} @ "info"}

    echo "check1"

    // get sum total surface area of all compartments receiving input.
    totsurf = 0
    openfile {fname} r
    compt = {readfile {fname} -linemode}
    while (! {eof {fname}})
        num_compts = {num_compts} + 1
        d = {getfield {cellpath}/{compt} dia}
        if ({strcmp {compt} "soma"} == 0)
            l = d;
        else
            l = {getfield {cellpath}/{compt} len}
        end
        surf = {PI}*{d}*{l}
        totsurf = {totsurf} + {surf}
        compt = {readfile {fname} -linemode}
    end
    closefile {fname}

    meansurf = {totsurf}/{num_compts}

    // calculate average synaptic conductance for rate of 1 Hz
    gsyn_uni = { calc_syn_integ {Gsyn} {t1} {t2} }

    echo "Implementing synaptic conductance as tonic leak..."
    echo "Total input surface area (microns2): " {{totsurf}*1e12}
    echo "Mean surface area of input compts (microns2): " {{meansurf}*1e12}
    echo "Total number of input events per second: " {{syn_rate}*{num_compts}}
    echo "Events per second for average compartment: " {syn_rate}
    echo "Events per second per square micron: " {{syn_rate}*{num_compts}/({totsurf}*1e12)}
    echo "Total amount of tonic conductance to be applied (nS): " {1e9*{gsyn_uni}*{syn_rate}*{num_compts}}
    echo "Tonic conductance density (S/m2): " {{gsyn_uni}*{syn_rate}*{num_compts}/{totsurf}}

    //cycle through each compartment and add correct amount of leakchan
    openfile {fname} r
    for (i = 1; i <= {num_compts}; i = i + 1)
        compt = {readfile {fname} -linemode}
        if (! {exists /{infostruct}/{compt}})
            echo "Error: " {compt} " not found in /" {infostruct}
            closefile {fname}
            quit
        end

        if ({getfield /{infostruct}/{compt} alloc} == 0)
            d = {getfield {cellpath}/{compt} dia}
            if ({strcmp {compt} "soma"} == 0)
                l = d;
            else
                l = {getfield {cellpath}/{compt} len}
            end
            surf = {PI}*{d}*{l}

            // input rate for this compartment based on surface area
            thisrate = {syn_rate} * {surf} / {meansurf}
         
            // conductance to add is product of unitary average and rate:
            gsyn = {{thisrate}*{gsyn_uni}}
    
            // copy leak channel from library to compartment, set values.
            copy /library/leakchan {cellpath}/{compt}/{s_name}
            setfield {cellpath}/{compt}/{s_name} \
                Gbar {gsyn} Ek {Echan}

            // pass messages
            addmsg {cellpath}/{compt} {cellpath}/{compt}/{s_name} VOLTAGE Vm
            addmsg {cellpath}/{compt}/{s_name} {cellpath}/{compt} CHANNEL Gk Ek    
                
            // Register the synapse in /{infostruct}
            setfield /{infostruct}/{compt} alloc 1 synname {s_name}

            // diagnostic

            echo "COMPT: " {compt} 
            echo "Surface Area (um^2): " {{surf}*1e12}
            echo "Normalized Input Rate (Hz): " {thisrate}
            echo "Constant conductance added (nS): " {{gsyn}*1e9}
        end
    end
    closefile {fname}
end