Example #1
0
    def create_equations(self):
        if self.timer is not None:
            self.model += b2.Equations(f"""
                dtimer/dt = {self.timer:f}  : second
                """)
            # This timer seems a bit odd: it increases more slowly than the regular
            # simulation time, and is only used in the threshold code, to prevent spikes.
            # It effectively increase the refractory time affecting spikes (but not dv/dt)
            # by a factor of 10 (to biologically unrealistic values).
            # TODO: should investigate effect of removing extended refractory period
        self.model = b2.Equations(str(self.model),
                                  v_rest="v_rest_e",
                                  tau="tau_e",
                                  v_eqm_synI="v_eqm_synI_e")
        if self.const_theta:
            self.model += b2.Equations("theta  : volt")
        else:
            self.model += b2.Equations("dtheta/dt = -theta / tc_theta  : volt")

        self.threshold = "v > (theta - theta_init + v_thresh_e)"
        if self.timer is not None:
            self.threshold = f"({self.threshold}) and (timer > refrac_e)"

        self.refractory = "refrac_e"

        self.reset = "v = v_reset_e"
        if self.timer is not None:
            self.reset += "; timer = 0*ms"
        if not self.const_theta:
            self.reset += "; theta += theta_plus_e"
Example #2
0
 def load_mod(modfile,bp):
     nakdic = json.load(open(modfile))
     fundic = dict([(j,k.split(":")[0]) for j,k in nakdic["fun"].items()])
     pardic = dict([(j,k) for j,k in nakdic["par"].items()])
     bifpar = [(k,pardic.pop(k)) for k in bp]
     sdelist = [[j,] + k.split(':') for j,k in nakdic['aux_odes'].items()]
     sdelist = [(i,":".join((str(S(j).subs(fundic).subs(fundic).subs(pardic)),k))) for i,j,k in sdelist]
     sdelist+= [('v', str(sympy.solve(nakdic['current_balance_eq'],'dv/dt')[0].subs(nakdic['currents']).subs(fundic).subs(fundic).subs(pardic))+":volt")]
     sde = brian2.Equations("d{}/dt = {}".format(*sdelist[0]))
     for i,j in sdelist[1:]:
         sde += brian2.Equations("d{}/dt = {}".format(i,j))
     return sde
Example #3
0
 def create_base_equations(self):
     """v : membrane potential of each neuron
             - in the absence of synaptic currents (`I_syn?`), this decays
               exponentially to the resting potential (`v_rest_e`) with
               time constant `tau_leak_e`
        I_synE: current due to excitatory synapses
             - this is proportional to the conductance of the excitatory
               synapses (`ge`) and the difference between the membrane
               potential (`v`) and the equilibrium potential of the
               excitatory synapses (v_eqm_e)
             - as implemented this implicitly includes a constant factor
               of the membrane resistance
        I_synI: current due to inhibitory synapses
        ge : conductance of excitatory synapses
             - this decays with time constant `tau_ge`
        gi : conductance of inhibitory synapses
             - this decays with time constant `tau_gi`
        v_eqm_synI_e: equilibrium potentials of inhibitory synapses in
                      an excitatory neuron
        v_eqm_synI_i: equilibrium potentials of inhibitory synapses in
                      an inhibitory neuron
        tau_e: time constant for membrane potential in an excitatory neuron
        tau_i: time constant for membrane potential in an inhibitory neuron
        tau_ge: conductance time constant for an excitatory synapse
        tau_gi: conductance time constant for an inhibitory synapse
     """
     self.model = b2.Equations("""
         dv/dt = ((v_rest - v) + (I_synE + I_synI) / nS) / tau  : volt (unless refractory)
         I_synE = ge * nS * (v_eqm_synE - v)  : amp
         I_synI = gi * nS * clip(v_eqm_synI - v, -100 * volt, 0 * mV)  : amp
         dge/dt = -ge / tau_ge  : 1
         dgi/dt = -gi / tau_gi  : 1
         """)
    def get_membrane_equation(self,
                              return_string=False):

        membrane_equation = Template(EquationHelper.membrane_eq_template)
        all_membrane_model_strings = dict(self.neuron_model_strings)
        all_membrane_model_strings.update(self.synaptic_excinh_model_strings)
        if self.custom_strings is not None:
            all_membrane_model_strings.update(self.custom_strings)

        try:
            membrane_equation = membrane_equation.substitute(all_membrane_model_strings)
        except KeyError:
            print('Undefined key in membrane equation')
        membrane_equation = str(membrane_equation)

        eq_lines = membrane_equation.splitlines()
        eq_lines = [line.strip() + '\n' for line in eq_lines if len(line.strip()) > 0]

        final_membrane_equation = ''.join(eq_lines)

        if return_string is True:
            return final_membrane_equation
        else:
            substitutables = {k: k + '_' + self.compartment for k in self.comp_specific_vars}
            compartment_eq = b2.Equations(final_membrane_equation, **substitutables)

            return compartment_eq
Example #5
0
 def __init__(self, tau_i, v_r, sigma, tau_sigma, beta_sigma):
     # self.equ = b.Equations('v = v1 + v2 : volt')
     # self.equ += b.Equations('dv1/dt = -v1/tau_i : volt')
     # self.equ += b.Equations('dv2/dt = -v2/tau_i : volt')
     self.equ = b.Equations('dv/dt = -v/tau_i : volt')
     self.threshold = 'rand() < sigma(v, dt)'
     self.reset = 'v = v_r'
Example #6
0
def main4():
    # Incorporation of refractory period
    bs.start_scope()

    tau = 10 * bs.ms
    # the (unless refractory) is necessary
    # refer to the documentation for more detail
    eqs = '''
    dv/dt = (1-v)/tau : 1 (unless refractory)
    '''
    equation = bs.Equations(eqs)
    # conditions for spiking models
    threshold = 'v>0.8'
    reset = 'v = -0.8'
    refractory = 5 * bs.ms
    G = bs.NeuronGroup(1, eqs, threshold=threshold, reset=reset, method='exact', refractory=refractory)

    state_monitor = bs.StateMonitor(G, 'v', record=0)
    spike_monitor = bs.SpikeMonitor(G)

    bs.run(50 * bs.ms)
    plt.plot(state_monitor.t / bs.ms, state_monitor.v[0])
    plt.xlabel('Time (ms)')
    plt.ylabel('v')
    plt.show()
Example #7
0
class Izhikevich(cells.Izhikevich):
    __doc__ = cells.Izhikevich.__doc__

    translations = build_translations(
        ('a', 'a', lambda **p: p["a"] * (1 / ms), lambda **p: p["a"] /
         (1 / ms)), ('b', 'b', lambda **p: p["b"] *
                     (1 / ms), lambda **p: p["b"] /
                     (1 / ms)), ('c', 'v_reset', lambda **p: p["c"] * mV,
                                 lambda **p: p["v_reset"] / mV),
        ('d', 'd', lambda **p: p["d"] * (mV / ms), lambda **p: p["d"] /
         (mV / ms)), ('i_offset', 'i_offset', lambda **p: p["i_offset"] * nA,
                      lambda **p: p["i_offset"] / nA))
    ### dv/dt = (0.04/ms/mV)*v*v ->>>> (0.04/ms/mV)*v**2
    eqs = brian2.Equations('''
        dv/dt = (0.04/ms/mV)*v*v + (5/ms)*v + 140*mV/ms - u + (i_offset + i_inj)/pF : volt (unless refractory)
        du/dt = a*(b*v-u)                                : volt/second (unless refractory)
        a                                                : 1/second
        b                                                : 1/second
        v_reset                                          : volt
        d                                                : volt/second
        i_offset                                         : amp
        i_inj                                            : amp
        ''')
    post_synaptic_variables = {'excitatory': 'v', 'inhibitory': 'v'}
    state_variable_translations = build_translations(
        ('v', 'v', lambda p: p * mV, lambda p: p / mV),
        ('u', 'u', lambda p: p * (mV / ms), lambda p: p / (mV / ms)))
    brian2_model = IzhikevichNeuronGroup
Example #8
0
def run_brian_sim(stim, dt, init_values, param_dict, method='exact'):
    # Model specification
    eqs = brian2.Equations("")
    eqs += brian2.Equations(
        "dV/dt = 1 / C * (Ie(t) + I_0 + I_1 - G * (V - El)) : volt (unless refractory)"
    )
    eqs += brian2.Equations("dI_0/dt = -k_0 * I_0 : amp (unless refractory)")
    eqs += brian2.Equations("dI_1/dt = -k_1 * I_1 : amp (unless refractory)")
    reset = ""
    reset = "\n".join([reset, "V = V_reset"])
    reset = "\n".join(
        [reset, "I_0 = R_0 * I_0 * exp(-k_0 * (t_ref - dt)) + A_0"])
    reset = "\n".join(
        [reset, "I_1 = R_1 * I_1 * exp(-k_1 * (t_ref - dt)) + A_1"])
    threshold = "V > Th_inf"
    refractory = param_dict['t_ref']

    Ie = brian2.TimedArray(stim, dt=dt)
    nrn = brian2.NeuronGroup(1,
                             eqs,
                             method=method,
                             reset=reset,
                             threshold=threshold,
                             refractory=refractory,
                             namespace=param_dict)
    nrn.V = init_values['V'] * brian2.units.volt
    nrn.I_0 = init_values['I_0'] * brian2.units.amp
    nrn.I_1 = init_values['I_1'] * brian2.units.amp

    monvars = [
        'V',
        'I_0',
        'I_1',
    ]
    mon = brian2.StateMonitor(nrn, monvars, record=True)

    num_step = len(stim)
    brian2.defaultclock.dt = dt
    brian2.run(num_step * dt)

    return (
        mon.t / brian2.units.second,
        mon.V[0] / brian2.units.volt,
        mon.I_0[0] / brian2.units.amp,
        mon.I_1[0] / brian2.units.amp,
    )
Example #9
0
    def get_neuron_equations(self):
        """
        Returns the membrane equations in a form that prints out nicely in Jupyter Notebook

        :return: b2.Equations object
        """

        s = self.get_membrane_equation(return_string=True)
        return b2.Equations(s)
Example #10
0
def simulate_Thl_cell_fig3(par, par_sim):
    num = par_sim['num']
    i_sensory_motor = par_sim['I_sm']

    # b2.set_device('cpp_standalone')
    b2.start_scope()

    eqs = b2.Equations('''    
    minfthl = 1/(1+exp(-(vt-thtmthl*mV)/(sigmthl*mV))): 1
    hinfthl =  1/(1+exp((vt-thththl*mV)/(sighthl*mV))): 1
    pinfthl = 1/(1+exp(-(vt-thtpthl*mV)/(sigpthl*mV))) :1
    rinfthl = 1/(1+exp((vt-thtrthl*mV)/(sigrthl*mV))) :1
    ahthl =  ah0thl*exp(-(vt-thtahthl*mV)/(sigahthl*mV)) :1
    bhthl =  bh0thl/(1+exp(-(vt-thtbhthl*mV)/(sigbhthl*mV))) :1
    tauhthl =  1/(ahthl+bhthl) *ms :second
    taurthl = taur0thl+taur1thl*exp(-(vt-thtrtauthl*mV)/(sigrtauthl*mV)) :second

    ilthl=glthl*(vt-vlthl):amp
    inathl=gnathl*minfthl*minfthl*minfthl*hthl*(vt-vnathl) :amp
    ikthl=gkthl*((0.75*(1-hthl))**4)*(vt-vkthl) :amp
    itthl=gtthl*pinfthl*pinfthl*rthl*(vt-vtthl) :amp
    iextthl:amp

    tmp_thl1 = sin(2*pi*(t-dsmthl)/tmsmthl) :1
    tmp_thl2 = sin(2*pi*(t-dsmthl+wsmthl)/tmsmthl) :1
    ym_thl1=1/(1+exp(-tmp_thl1/sigym)):1
    ym_thl2=1/(1+exp(-tmp_thl2/sigym)):1
    ithl_sm=imsmthl*ym_thl1*(1-ym_thl2) :amp
    
    membrane_Ithl = -(ilthl+inathl+ikthl+itthl)+iextthl+ithl_sm:amp    
    drthl/dt=phirthl*(rinfthl-rthl)/taurthl :1
    dhthl/dt=phihthl*(hinfthl-hthl)/tauhthl :1 
    dvt/dt = membrane_Ithl/cmthl : volt
    ''')

    neuron = b2.NeuronGroup(
        num,
        eqs,
        method=par_sim['integration_method'],
        dt=par_sim['dt'],
        threshold='vt>-55*mV',
        refractory='vt>-55*mV',
        namespace=par,
    )

    neuron.vt = par['v0']
    neuron.hthl = "hinfthl"
    neuron.rthl = "rinfthl"
    neuron.iextthl = par['iext']

    state_monitor = b2.StateMonitor(neuron, ["vt", "ithl_sm"], record=True)

    net = b2.Network(neuron)
    net.add(state_monitor)
    net.run(par_sim['simulation_time'])

    return state_monitor
Example #11
0
    def get_compartment_equations(self, compartment_name):
        membrane_eq = self.get_membrane_equation(return_string=True)

        substitutables = {
            key: key + '_' + compartment_name
            for key in self.compartment_vars_and_consts
        }
        compartment_eq = b2.Equations(membrane_eq, **substitutables)

        return compartment_eq
Example #12
0
    def create_equations(self):
        self.model = b2.Equations(str(self.model),
                                  v_rest="v_rest_i",
                                  tau="tau_i",
                                  v_eqm_synI="v_eqm_synI_i")

        self.threshold = "v > v_thresh_i"

        self.refractory = "refrac_i"

        self.reset = "v = v_reset_i"
Example #13
0
def run_brian_sim(stim, dt, init_values, param_dict, method='exact'):
    # Model specification
    eqs = brian2.Equations("")
    eqs += brian2.Equations(
        "dV/dt = 1 / C * (Ie(t) - G * (V - El)) : volt (unless refractory)")
    eqs += brian2.Equations(
        "dTh_s/dt = -b_s * Th_s : volt (unless refractory)")
    reset = ""
    reset = "\n".join([reset, "V = a_r * V + b_r"])
    reset = "\n".join([reset, "Th_s = Th_s + a_s"])
    threshold = "V > Th_inf + Th_s"
    refractory = param_dict['t_ref']

    Ie = brian2.TimedArray(stim, dt=dt)
    nrn = brian2.NeuronGroup(1,
                             eqs,
                             method=method,
                             reset=reset,
                             threshold=threshold,
                             refractory=refractory,
                             namespace=param_dict)
    nrn.V = init_values['V'] * brian2.units.volt
    nrn.Th_s = init_values['Th_s'] * brian2.units.volt

    monvars = [
        'V',
        'Th_s',
    ]
    mon = brian2.StateMonitor(nrn, monvars, record=True)

    num_step = len(stim)
    brian2.defaultclock.dt = dt
    brian2.run(num_step * dt)

    return (
        mon.t / brian2.units.second,
        mon.V[0] / brian2.units.volt,
        mon.Th_s[0] / brian2.units.volt,
    )
Example #14
0
    def get_membrane_equation(self,
                              substitute_ad_hoc=None,
                              return_string=True):
        """
        Compiles the membrane equation from the template for use in Brian2.
        This should be the only function where the template equation is used.

        :param substitute_ad_hoc:
        :param return_string:
        :return:
        """

        # Get the generic template
        neuron_eqs_template = Template(self.membrane_eq_template)

        # Do ad hoc substitutions, overriding any definitions in full_model_defns
        if substitute_ad_hoc is not None:
            neuron_eqs_template2 = Template(
                neuron_eqs_template.safe_substitute(substitute_ad_hoc))
        else:
            neuron_eqs_template2 = neuron_eqs_template

        # Make substitutions in full_model_defns
        neuron_eqs_template2 = Template(
            neuron_eqs_template2.safe_substitute(self.full_model_defns))

        # Deal with extra placeholders in the eq template
        nullify_placeholders_dict = {
            k: ''
            for k in PointNeuron.all_template_placeholders
        }
        neuron_eqs_template_wo_placeholders = neuron_eqs_template2.substitute(
            nullify_placeholders_dict)

        # Stringify the equations
        neuron_eqs_string = str(neuron_eqs_template_wo_placeholders)
        eq_lines = neuron_eqs_string.splitlines()
        eq_lines = [
            line.strip() + '\n' for line in eq_lines if len(line.strip()) > 0
        ]
        model_membrane_equation = ''.join(eq_lines)

        if return_string is True:
            return model_membrane_equation
        else:
            #substitutables = {k: k+'_'+self.compartment for k in self.comp_specific_vars}
            #compartment_eq = b2.Equations(self.model_membrane_equation, **substitutables)
            return b2.Equations(model_membrane_equation)
Example #15
0
    def get_compartment_equations(self, compartment_name):
        """
        Compiles the membrane equation and adds compartment name to all compartment-specific variables

        :param string compartment_name: name of the compartment
        :return: string
        """
        membrane_eq = self.get_membrane_equation(return_string=True)

        substitutables = {
            key: key + '_' + compartment_name
            for key in self.compartment_vars_and_consts
        }
        compartment_eq = b2.Equations(membrane_eq, **substitutables)

        return compartment_eq
Example #16
0
    def get_membrane_equation(self,
                              substitute_ad_hoc=None,
                              return_string=True):
        """
        Compiles the membrane equation from the template for use in Brian2.
        This should be the only function where the template equation is used.

        :param dict substitute_ad_hoc: dictionary of temporary values to use in the equation template
        :param bool return_string: If True, returns equations as a string. Otherwise, returns a b2.Equations object.
        :return: string (or b2.Equations object)
        """

        # Get the generic template
        neuron_eqs_template = Template(self.membrane_eq_template)

        # Do ad hoc substitutions, overriding any definitions in full_model_defns
        if substitute_ad_hoc is not None:
            neuron_eqs_template2 = Template(
                neuron_eqs_template.safe_substitute(substitute_ad_hoc))
        else:
            neuron_eqs_template2 = neuron_eqs_template

        # Make substitutions in full_model_defns
        neuron_eqs_template2 = Template(
            neuron_eqs_template2.safe_substitute(self.full_model_defns))

        # Deal with extra placeholders in the eq template
        nullify_placeholders_dict = {
            k: ''
            for k in PointNeuron.all_template_placeholders
        }
        neuron_eqs_template_wo_placeholders = neuron_eqs_template2.substitute(
            nullify_placeholders_dict)

        # Stringify the equations
        neuron_eqs_string = str(neuron_eqs_template_wo_placeholders)
        eq_lines = neuron_eqs_string.splitlines()
        eq_lines = [
            line.strip() + '\n' for line in eq_lines if len(line.strip()) > 0
        ]
        model_membrane_equation = ''.join(eq_lines)

        if return_string is True:
            return model_membrane_equation
        else:
            return b2.Equations(model_membrane_equation)
from ...timeseries import TSContinuous, TSEvent
from ..layer import Layer
from rockpool.utilities import TimedArray as TAShift

from typing import Optional, Union, Tuple, List

# - Type alias for array-like objects
ArrayLike = Union[np.ndarray, List, Tuple]

# - Configure exports
__all__ = ["FFExpSynBrian", "eqSynapseExp"]

# - Equations for an exponential synapse
eqSynapseExp = b2.Equations(
    """
    dI_syn/dt = (-I_syn + I_inp(t, i)) / tau_s  : amp                       # Synaptic current
    tau_s                                       : second                    # Synapse time constant
"""
)


## - FFExpSynBrian - Class: define an exponential synapse layer (spiking input)
class FFExpSynBrian(Layer):
    """ *DEPRECATED* Define an exponential synapse layer (spiking input), with a Brian2 backend
    """

    ## - Constructor
    def __init__(
        self,
        weights: Union[np.ndarray, int] = None,
        dt: float = 0.1 * ms,
        noise_std: float = 0 * mV,
Example #18
0
class HH_cond_exp(cells.HH_cond_exp):
    __doc__ = cells.HH_cond_exp.__doc__

    translations = build_translations(
        ('gbar_Na', 'gbar_Na', lambda **p: p["gbar_Na"] * uS,
         lambda **p: p["gbar_Na"] / uS),
        ('gbar_K', 'gbar_K', lambda **p: p["gbar_K"] * uS,
         lambda **p: p["gbar_K"] / uS),
        ('g_leak', 'g_leak', lambda **p: p["g_leak"] * uS,
         lambda **p: p["g_leak"] / uS),
        ('cm', 'c_m', lambda **p: p["cm"] * nF, lambda **p: p["c_m"] / nF),
        ('v_offset', 'v_offset', lambda **p: p["v_offset"] * mV,
         lambda **p: p["v_offset"] / mV),
        ('e_rev_Na', 'e_rev_Na', lambda **p: p["e_rev_Na"] * mV,
         lambda **p: p["e_rev_Na"] / mV),
        ('e_rev_K', 'e_rev_K', lambda **p: p["e_rev_K"] * mV,
         lambda **p: p["e_rev_K"] / mV),
        ('e_rev_leak', 'e_rev_leak', lambda **p: p["e_rev_leak"] * mV,
         lambda **p: p["e_rev_leak"] / mV),
        ('e_rev_E', 'e_rev_e', lambda **p: p["e_rev_E"] * mV,
         lambda **p: p["e_rev_e"] / mV),
        ('e_rev_I', 'e_rev_i', lambda **p: p["e_rev_I"] * mV,
         lambda **p: p["e_rev_i"] / mV),
        ('tau_syn_E', 'tau_syn_e', lambda **p: p["tau_syn_E"] * ms,
         lambda **p: p["tau_syn_e"] / ms),
        ('tau_syn_I', 'tau_syn_i', lambda **p: p["tau_syn_I"] * ms,
         lambda **p: p["tau_syn_i"] / ms),
        ('i_offset', 'i_offset', lambda **p: p["i_offset"] * nA,
         lambda **p: p["i_offset"] / nA))
    eqs = brian2.Equations('''
        dv/dt =  (g_leak*(e_rev_leak-v) - gbar_Na*(m*m*m)*h*(v-e_rev_Na) - gbar_K*(n*n*n*n)*(v-e_rev_K) + i_syn + i_offset + i_inj)/c_m : volt
        dm/dt  = (alpham*(1-m)-betam*m) : 1
        dn/dt  = (alphan*(1-n)-betan*n) : 1
        dh/dt  = (alphah*(1-h)-betah*h) : 1
        alpham = (0.32/mV)*(13*mV-v+v_offset)/(exp((13*mV-v+v_offset)/(4*mV))-1.)/ms  : Hz
        betam  = (0.28/mV)*(v-v_offset-40*mV)/(exp((v-v_offset-40*mV)/(5*mV))-1)/ms   : Hz
        alphah = 0.128*exp((17*mV-v+v_offset)/(18*mV))/ms                                 : Hz
        betah  = 4./(1+exp((40*mV-v+v_offset)/(5*mV)))/ms                                 : Hz
        alphan = (0.032/mV)*(15*mV-v+v_offset)/(exp((15*mV-v+v_offset)/(5*mV))-1.)/ms : Hz
        betan  = .5*exp((10*mV-v+v_offset)/(40*mV))/ms                                    : Hz
        e_rev_Na               : volt
        e_rev_K                : volt
        e_rev_leak             : volt
        gbar_Na                : siemens
        gbar_K                 : siemens
        g_leak                 : siemens
        v_offset               : volt
        c_m                    : farad
        i_offset               : amp
        i_inj                  : amp
    ''') + conductance_based_exponential_synapses
    recordable = ['spikes', 'v', 'gsyn_exc', 'gsyn_inh', 'm', 'n', 'h']
    post_synaptic_variables = {'excitatory': 'ge', 'inhibitory': 'gi'}
    state_variable_translations = build_translations(
        ('v', 'v', lambda p: p * mV, lambda p: p / mV),
        ('gsyn_exc', 'ge', lambda p: p * uS, lambda p: p / uS),
        ('gsyn_inh', 'gi', lambda p: p * uS, lambda p: p / uS),
        ('h', 'h', lambda p: p * 1, lambda p: p * 1),
        ('m', 'm', lambda p: p * 1, lambda p: p * 1),
        ('n', 'n', lambda p: p * 1, lambda p: p * 1))
    brian2_model = BiophysicalNeuronGroup
Example #19
0
from copy import deepcopy
import brian2
from brian2 import mV, ms, nF, nA, uS, Hz, nS
from pyNN.standardmodels import cells, build_translations
from ..cells import (ThresholdNeuronGroup, SpikeGeneratorGroup, PoissonGroup,
                     BiophysicalNeuronGroup, AdaptiveNeuronGroup,
                     AdaptiveNeuronGroup2, IzhikevichNeuronGroup)
import logging

logger = logging.getLogger("PyNN")

leaky_iaf = brian2.Equations('''
                dv/dt = (v_rest-v)/tau_m + (i_syn + i_offset + i_inj)/c_m  : volt (unless refractory)
                tau_m                   : second
                c_m                     : farad
                v_rest                  : volt
                i_offset                : amp
                i_inj                   : amp
            ''')
# give v_thresh a different name
adexp_iaf = brian2.Equations('''
                dv/dt = (delta_T*gL*exp((-v_thresh + v)/delta_T) + I + gL*(v_rest - v) - w )/ c_m : volt (unless refractory)
                dw/dt = (a*(v-v_rest) - w)/tau_w  : amp
                gL    =  c_m / tau_m    : siemens
                I = i_syn + i_inj + i_offset : amp
                a                       : siemens
                tau_m                   : second
                tau_w                   : second
                c_m                     : farad
                v_rest                  : volt
                v_spike                 : volt
    def make_neuron_equations(self):
        # Topology here is: (POST) basal -> soma -> a0 -> a1 -> ... (PRE)
        # Multiple different indexes:
        #  - C, g_leak are indexed 0...N from basal...last apical
        #  - Apical dendrite compartments are indexed 0...(N-2)
        #  - Ra is indexed 0...(N-1) from basal...last apical
        # In legacy code, vm of soma is vm, not vm_soma. To keep things separate & clear, however,
        # we will replace vm_soma->vm only in the very end

        # For convenience
        R_axial = self.neuron_parameters['Ra']
        C = self.neuron_parameters['C']
        g_leak = self.neuron_parameters['g_leak']

        # Dendritic current templates
        I_dendr_basal = 'I_dendr = gapre*(vmpre-vmself) : amp'
        I_dendr_2way = 'I_dendr = gapre*(vmpre-vmself) + gapost*(vmpost-vmself) : amp'
        I_dendr_last_apical = 'I_dendr = gapost*(vmpost-vmself) : amp'

        # Basal compartment
        temp_eq = b2.Equations(I_dendr_basal,
                               I_dendr='I_dendr_basal', vmself='vm_basal', vmpre='vm_soma',
                               gapre=1 / (R_axial[0]))
        self.basal_compartment.add_external_current('I_dendr_basal', str(temp_eq))
        eq_basal = self.basal_compartment.get_compartment_equations('basal')
        eq_basal = b2.Equations(str(eq_basal), C=C[0], g_leak=g_leak[0])

        # The soma
        temp_eq = b2.Equations(I_dendr_2way,
                               I_dendr='I_dendr_soma', vmself='vm_soma',
                               vmpre='vm_a0', vmpost='vm_basal',
                               gapre=1 / (R_axial[1]), gapost=1 / (R_axial[0]))
        self.soma_compartment.add_external_current('I_dendr_soma', str(temp_eq))
        eq_soma = self.soma_compartment.get_compartment_equations('soma')

        eq_soma = b2.Equations(str(eq_soma), C=C[1], g_leak=g_leak[1])

        # Finally, go through all apical compartments but not the last one
        n_apical = self.n_apical
        eq_apicals = []
        post_compartment = 'soma'
        for i in range(n_apical-1):
            temp_eq = b2.Equations(I_dendr_2way,
                                   I_dendr='I_dendr_a%d'%i, vmself='vm_a%d'%i,
                                   vmpre='vm_a%d'%(i+1), vmpost='vm_'+post_compartment,
                                   gapre=1 / (R_axial[i+2]), gapost=1 / (R_axial[i+1]))
            self.apical_compartments[i].add_external_current('I_dendr_a%d'%i, str(temp_eq))
            eq_apical = self.apical_compartments[i].get_compartment_equations('a%d'%i)
            eq_apical = b2.Equations(str(eq_apical),
                                   C=C[i+2], g_leak=g_leak[i+2])
            eq_apicals.append(eq_apical)
            post_compartment = 'a%d'%i


        # The last apical compartment
        last_ix = n_apical - 1
        if n_apical == 1:
            post_compartment = 'soma'
        else:
            post_compartment = 'a%d' % (last_ix - 1)

        vm_post = 'vm_'+post_compartment

        temp_eq = b2.Equations(I_dendr_last_apical,
                               I_dendr='I_dendr_a%d'%last_ix, vmself='vm_a%d' % last_ix,
                               vmpost=vm_post, gapost=1 / (R_axial[-1]))
        # R_axial[-1] can be wrong but we keep it in this legacy version

        self.apical_compartments[last_ix].add_external_current('I_dendr_a%d' % last_ix, str(temp_eq))
        eq_apical = self.apical_compartments[last_ix].get_compartment_equations('a%d' % last_ix)
        eq_apical = b2.Equations(str(eq_apical),
                                 C=C[last_ix + 2], g_leak=g_leak[last_ix + 2])
        eq_apicals.append(eq_apical)

        # Combine all the equations into one & replace vm_soma -> vm

        final_eq = eq_basal+eq_soma
        for i in range(n_apical):
            final_eq += eq_apicals[i]

        self.final_eqs = b2.Equations(str(final_eq), vm_soma='vm')
Example #21
0
def find_ini_brian():

    import pylab, brian2, brianutils, os, json, sympy, scipy, sys, \
        datetime, shelve, autoutils, contextlib
    from sympy import S

    units= dict(brian2.units.__dict__.items()
                + brian2.units.allunits.__dict__.items()
                + brian2.__dict__.items())
    unitlist=["mV","ms","cm2","uF","psiemens","um2","msiemens","cm"]
    baseunits=[(k,float(eval(k,units).base)) for k in unitlist]

    p = {"simfile"  : "sim_DNap_2015-12-14_16:55:14.603625.shv",
         "modfile"  : "cfg/wangBuzsaki_brian.json",      #This is our model
         "contfile" : "dat/cont_WB.json",   #This is what brian produces and hands to auto
         "workdir"  : os.getenv("HOME") + "/Uni/CNS/3.Semester/schreiberlab/excitationblock/model0/final",
         "dt"       : "0.05*ms",
         "bifpar"   : {
           "I" : ["0.0* uA/cm2"],
           "Cm" : ["1.0*uF/cm2","1.1*uF/cm2","1.4*uF/cm2","1.41*uF/cm2","1.42*uF/cm2"]
           }
         }

    os.chdir(p["workdir"])
    #Now, we define how to load in the model in a nice pythonic way and sort them
    #in a way that brian will understand them.
    def load_mod(modfile,bp):
        nakdic = json.load(open(modfile))
        fundic = dict([(j,k.split(":")[0]) for j,k in nakdic["fun"].items()])
        pardic = dict([(j,k) for j,k in nakdic["par"].items()])
        bifpar = [(k,pardic.pop(k)) for k in bp]
        sdelist = [[j,] + k.split(':') for j,k in nakdic['aux_odes'].items()]
        sdelist = [(i,":".join((str(S(j).subs(fundic).subs(fundic).subs(pardic)),k))) for i,j,k in sdelist]
        sdelist+= [('v', str(sympy.solve(nakdic['current_balance_eq'],'dv/dt')[0].subs(nakdic['currents']).subs(fundic).subs(fundic).subs(pardic))+":volt")]
        sde = brian2.Equations("d{}/dt = {}".format(*sdelist[0]))
        for i,j in sdelist[1:]:
            sde += brian2.Equations("d{}/dt = {}".format(i,j))
        return sde

    ## FIND INITIAL STEADY STATE ##
    sde = load_mod(p["modfile"],p['bifpar'].keys())
    ode = brianutils.sde2ode(sde)
    diffuterms=dict([(k[3:],(S(j).coeff(k)**2).subs(baseunits)) for i,j in sde.eq_expressions for k in sde.stochastic_variables if S(j).coeff(k)!=0])

    ## ADD PAR ##
    for j,k in p["bifpar"].items():
      ode += brian2.Equations("{} : {}".format(j,repr(eval(k[0],units).dim)))

    brian2.defaultclock.dt = eval(p["dt"], units)
    G = brian2.NeuronGroup(1, model=ode, method="rk4",
                           threshold='not_refractory and (v>5*mV)',
                           refractory='v>-40*mV')

    # PAR INIT #
    for j,k in p["bifpar"].items():
      setattr(G,j,eval(k[0],units))

    # STATE INIT #
    G.v= eval("-66 * mV", units)

    states = brian2.StateMonitor(G, ode.eq_names, record=True)
    spikes = brian2.SpikeMonitor(G)
    net = brian2.Network(G,states,spikes)
    duration = eval("500 * ms",units)
    net.run(duration)

    autobifpar = dict([(i,float(eval(j[0],units))) for i,j in p['bifpar'].items()])

    ## CREATE ADJOINT LINEAR SYSTEM ##

    baseunits2 = [('mV', 1), ('ms', 1), ('cm2', 1), ('uF', 1), ('psiemens', 1), ('um2', 1), ('msiemens', 1), ('cm', 1)]
    varrhs = [(i,sympy.S(j).subs(baseunits2))
                    for i,j in ode.eq_expressions]

    # varrhs_2 = [(i,sympy.S(j).subs(baseunits))
    #                 for i,j in ode.eq_expressions]

    varrhs.sort(cmp=lambda x,y:cmp(x[0],y[0]),reverse=True)
    var,rhs = zip(*varrhs);
    advar = sympy.S(["ad{}".format(k) for k in var])
    J = [[S(i).diff(j) for j in var] for i in rhs]
    J = [[j.subs(baseunits) for j in k] for k in J]
    adlinsys = [str(k) for k in
                (sympy.S("lam")*sympy.eye(len(advar))-sympy.Matrix(J).T)*sympy.Matrix(advar)]
    prcnorm=str((sympy.Matrix(sympy.S(advar)).T*sympy.Matrix(sympy.S(rhs)))[0,0] - sympy.S("dotZF/period"))

    # Ipar = eval("1.2 * uA/cm2", units) # LC
    spikecriterion = [str(S(k).subs([(i,"{}_left".format(i)) for i in var]))
                      for j,k in zip(var,rhs) if j=="v"]

    #Hier kommt das Pythondings von Jan-Hendrik zum Einsatz!
    if "A" in autobifpar:
        autobifpar.pop("A")

    unames,pnames= autoutils.writeFP('tm_new',
        bifpar=autobifpar, rhs=rhs, var=var,
        bc=['{0}_left-{0}_right'.format(v) for v in var] + spikecriterion,
        ic=[])

    inivals = ([float(getattr(states,j)[0][-1]) for j in var])

    #convert first value (V) from V to mV.
    inivals[0] *= 1000
    return unames, pnames, inivals, autobifpar
Example #22
0
 def create_equations(self):
     self.model = b2.Equations("w : 1")
     self.pre_eqn = "g{}_post += w".format(self.pre_conn_type)
     self.post_eqn = ""
Example #23
0
    def create_stdp_equations(self):
        if self.stdp_rule == "original":
            # original code from Diehl & Cooke (2015) repository
            # An implementation of the nearest-spike minimal triplet
            # model of Pfister & Gerstner (2006)
            # NOTES:
            # * the sign of the weight pre-synaptic weight update
            #   appears to be wrong compared to PG06
            self.model += b2.Equations("""
                dpre/dt = -pre/(tc_pre_ee)  : 1 (event-driven)
                dpost1/dt  = -post1/(tc_post_1_ee)  : 1 (event-driven)
                dpost2/dt  = -post2/(tc_post_2_ee)  : 1 (event-driven)
                """)
            self.pre_eqn += """
                pre = 1.
                w = clip(w + nu_ee_pre * post1, 0, wmax_ee)
                """
            self.post_eqn += """
                w = clip(w + nu_ee_post * pre * post2, 0, wmax_ee)
                post1 = 1.
                post2 = 1.
                """
        elif self.stdp_rule == "minimal-triplet":
            # Minimal (visual cortex) model of Pfister & Gerstner (2006)
            # Mapping of notation to PG06 and DC15:
            # pre = r_1 = pre
            # tc_pre = \tau_+ = tc_pre_ee
            # post1 = o_1 = post1
            # post2 = o_2 = post2
            # tc_post1 = \tau_- = tc_post_1_ee
            # tc_post2 = \tau_y = tc_post_2_ee
            # nu_pair_pre = A^-_2 = nu_ee_pre
            # nu_triple_post = A^+_3 = nu_ee_post
            self.model += b2.Equations("""
                dpre/dt = -pre / tc_pre  : 1 (event-driven)
                dpost1/dt  = -post1 / tc_post1  : 1 (event-driven)
                dpost2/dt  = -post2 / tc_post2  : 1 (event-driven)
                """)
            self.pre_eqn += """
                w = clip(w - post1 * nu_pair_pre, 0, wmax)
                pre = 1.0
                """
            self.post_eqn += """
                w = clip(w + pre * nu_triple_post * post2, 0, wmax)
                post1 = 1.0
                post2 = 1.0
                """
        elif self.stdp_rule == "full-triplet":
            # Full model of Pfister & Gerstner (2006)
            # Mapping of notation to PG06 and DC15:
            # pre1 = r_1 = pre
            # pre2 = r_2  (neglected in minimal model)
            # tc_pre1 = \tau_+ = tc_pre_ee
            # tc_pre2 = \tau_x  (neglected in minimal model)
            # post1 = o_1 = post1
            # post2 = o_2 = post2
            # tc_post1 = \tau_- = tc_post_1_ee
            # tc_post2 = \tau_y = tc_post_2_ee
            # nu_pair_pre = A^-_2 = nu_ee_pre
            # nu_triple_pre = A^-_3  (neglected in minimal model)
            # nu_pair_post = A^+_2  (neglected in minimal model)
            # nu_triple_post = A^+_3 = nu_ee_post
            self.model += b2.Equations("""
                dpre1/dt = -pre1 / tc_pre1  : 1 (event-driven)
                dpre2/dt = -pre2 / tc_pre2  : 1 (event-driven)
                dpost1/dt  = -post1 / tc_post1  : 1 (event-driven)
                dpost2/dt  = -post2 / tc_post2  : 1 (event-driven)
                """)
            self.pre_eqn += """
                w = clip(w - post1 * (nu_pair_pre + nu_triple_pre * pre2), 0, wmax)
                pre1 = 1.0
                pre2 = 1.0
                """
            self.post_eqn += """
                w = clip(w + pre1 * (nu_pair_post + nu_triple_post * post2), 0, wmax)
                post1 = 1.0
                post2 = 1.0
                """
        if self.stdp_rule == "powerlaw":
            # inferred code from Diehl & Cooke (2015)
            self.model += b2.Equations("""
                dpre/dt = -pre/ tc_pre  : 1 (event-driven)
                """)
            self.pre_eqn += """
                pre = pre + 1.0
                """
            self.post_eqn += """
                w = clip(w + nu * (pre - tar) * (wmax - w)**mu, 0, wmax)
                """
        if self.stdp_rule == "exponential":
            # inferred code from Diehl & Cooke (2015)
            self.model += b2.Equations("""
                dpre/dt = -pre/ tc_pre  : 1 (event-driven)
                """)
            self.pre_eqn += """
                pre = pre + 1.0
                """
            self.post_eqn += """
                w = clip(w + nu * (pre * exp(-beta * w) - tar * exp(-beta * (wmax - w))), 0, wmax)
                """
        if self.stdp_rule == "symmetric":
            # inferred code from Diehl & Cooke (2015)
            self.model += b2.Equations("""
                dpre/dt = -pre/ tc_pre  : 1 (event-driven)
                dpost/dt  = -post / tc_post  : 1 (event-driven)

                """)
            self.pre_eqn += """
                 w = clip(w - nu_pre * pre * w**mu, 0, wmax)
                 pre = pre + 1.0
                 """
            self.post_eqn += """
                 w = clip(w + nu_post * (pre - tar) * (wmax - w)**mu, 0, wmax)
                 post = post + 1.0
                 """
        if self.stdp_rule == "clopath2010":
            # TODO: try Clopath et al. 2010 rule
            # not in DC15, but would be nice to try this sometime:
            # spike-timing dependent plasticity perhaps more bio-physically
            # mediated by the post-synaptic membrane voltage
            pass
Example #24
0
def Simulate(g, inp, seed=1337):
    """Simulation of the Brunel network with
  relative strength between IPSP and EPSP g and 
  external input parameter inp.
  Inp=1 is the minimum amount of external stimulation to observe sustained 
  activity in the full network (12 500 neurons).
  """

    br.set_device('cpp_standalone')
    br.prefs.codegen.target = 'weave'

    # NETWORK INITIALIZATION
    np.random.seed(seed)  # set seed for reproducibility of simulations
    random.seed(seed)  # set seed for reproducibility of simulations

    # =============================================================================
    # PARAMETERS
    # Simulation parameters
    simdt = 0.01 * br.ms
    simtime = sim_time * br.second
    br.defaultclock.dt = simdt  # Brian's default sim time step
    dt = br.defaultclock.dt / br.second

    # scaling parameter to the true on of Brunel 2000
    N_true = 12500
    delay = syn_delay * br.ms  # Synaptic delay
    J = Vm_jump_after_EPSP * downscale * br.mV  # jump of membrane potential after EPSP

    # Network numbers parameters
    N = int(N_true / downscale)  # number of Neuron
    C = int(connectivity * N)  # number of connexions per neuron
    sparseness = C / float(N)
    f_exc = 0.8  # fraction of exitatory synapses
    Ce = int(C * f_exc)  # number of exitatory connexions
    NE = int(N * f_exc)  # Number of excitatory cells
    NI = N - NE  # Number of inhibitory cells
    CE_true = int(N_true * connectivity * f_exc)

    # Neurons parameters
    tau = 20.0 * br.ms  # membrane time constant
    mu_0 = 0. * br.mV  # offset to the membrane
    Vr = mu_0 + 10.0 * br.mV  # potential of reset after spiking
    theta = mu_0 + 20.0 * br.mV  # Spiking threshold
    taurefr = 2. * br.ms  # time constant of refractory period

    # Synapse parameters
    g = float(g)  # relative strength between IPSP and EPSP

    # parameter of external population
    Inp = float(inp)  # coefficient multiplying nu_theta
    nu_theta = theta / (Ce * J * tau
                        )  # minimal required input frequency for firing

    # =============================================================================
    # INITIALIZE NEURONS GROUP
    # Main group
    eqs_neurons = br.Equations('''
  	dV/dt = (-V +  mu_0)/tau : volt (unless refractory)
  	''')
    Group=br.NeuronGroup(N, model=eqs_neurons,\
                         threshold='V>=theta', reset='V=Vr', \
                         refractory=taurefr, method='euler')
    Group.V = np.linspace(mu_0 / br.mV - 20, theta / br.mV, N) * br.mV

    # external group

    # =============================================================================
    # SYNAPSES DEFINITION AND CONNEXIONS
    # The implementation of connections come from ExcInhNet_Ostojic2014_Brunel2000_brian2.py
    # written by Aditya Gilra to connect the synapses.

    # Main group synapses
    sparseness_e = Ce / float(NE)
    sparseness_i = (1 - f_exc) * C / float(NI)
    con = br.Synapses(Group,
                      Group,
                      'w:volt',
                      on_pre='V_post += w',
                      method='euler')
    # Connections from some Exc/Inh neurons to each neuron
    random.seed(seed)  # set seed for reproducibility of simulations
    conn_i = []
    conn_j = []
    for j in range(0, N):
        # sample Ce number of neuron indices out of NE neurons
        preIdxsE = random.sample(range(NE), Ce)
        # sample Ci=C-excC number of neuron indices out of inhibitory neurons
        preIdxsI = random.sample(range(NE, N), C - Ce)
        # connect these presynaptically to i-th post-synaptic neuron
        # choose the synapses object based on whether post-syn nrn is exc or inh
        conn_i += preIdxsE
        conn_j += [j] * Ce
        conn_i += preIdxsI
        conn_j += [j] * (C - Ce)
    con.connect(i=conn_i, j=conn_j)
    con.delay = delay
    con.w['i<NE'] = J
    con.w['i>=NE'] = -g * J

    #  # save connectivity matrix of the network for post-analysis purpose
    #  # safe to comment if you are not interested in this information
    #  struct = np.zeros((N,N))
    #  for i,j in zip(conn_i, conn_j):
    #    struct[i,j] = 1
    #  utils.save('brunel_struct_seed={}.npy'.format(seed), struct)

    # EXTERNAL POPULATION
    #correct external population firing rate for downscaling
    if g > 4:
        approx_rate = ((Inp - 1) * nu_theta) / (g * 0.25 - 1) / N
        rate_ext_0 = Ce * Inp * nu_theta
        rate_balance = Ce * ((1/downscale) - 1) *\
                            (Inp * nu_theta + approx_rate*(1 + 0.25*g**2)) /\
                            (1 + g**2)
        rate_corrected = (rate_ext_0 + rate_balance) / Ce
    else:
        rate_corrected = Inp * nu_theta
    print(Inp * nu_theta, rate_corrected)

    PI = br.PoissonInput(Group, 'V', N=Ce, rate=rate_corrected, weight=J)

    # =============================================================================
    # SIMULATION

    #np.random.seed(seed)
    #random.seed(seed)

    # Setting up monitors
    M = br.SpikeMonitor(Group)
    LFP = br.PopulationRateMonitor(Group)

    br.run(simtime, report='text')

    # saving population firing rate and spike trains
    fr = [
        LFP.t / br.ms,
        LFP.smooth_rate(window='flat', width=0.5 * br.ms) / br.Hz
    ]
    sp = M.spike_trains()
    br.device.reinit()
    return sp, fr
    sde = brian2.Equations("d{}/dt = {}".format(*sdelist[0]))
    for i, j in sdelist[1:]:
        sde += brian2.Equations("d{}/dt = {}".format(i, j))
    return sde


## FIND INITIAL STEADY STATE ##
sde = load_mod(p["modfile"], p['bifpar'].keys())
ode = brianutils.sde2ode(sde)
diffuterms = dict([(k[3:], (S(j).coeff(k)**2).subs(baseunits))
                   for i, j in sde.eq_expressions
                   for k in sde.stochastic_variables if S(j).coeff(k) != 0])

## ADD PAR ##
for j, k in p["bifpar"].items():
    ode += brian2.Equations("{} : {}".format(j, repr(eval(k[0], units).dim)))

brian2.defaultclock.dt = eval(p["dt"], units)
G = brian2.NeuronGroup(1,
                       model=ode,
                       method="rk4",
                       threshold='not_refractory and (v>5*mV)',
                       refractory='v>-40*mV')

# PAR INIT #
for j, k in p["bifpar"].items():
    setattr(G, j, eval(k[0], units))

# STATE INIT #
G.v = eval("-66 * mV", units)