예제 #1
0
 def _event_builder(self, events):
     """
     From events yield lems.OnCondition objects
     """
     # loop ober the events of the group
     for event in events:
         event_out = lems.EventOut(event)  # output (e.g. spike)
         # get threshold condition and add it to on_cond
         on_cond_code = events[event]['threshold']['code']
         on_cond = lems.OnCondition(renderer.render_expr(on_cond_code))
         on_cond.add_action(event_out)
         # if event is not in model ports add it
         if event not in self._component_type.event_ports:
             self._component_type.add(
                 lems.EventPort(name=event, direction='out'))
         # check and add reset equations
         if 'reset' in events[event]:
             reset_code = events[event]['reset']['code']
             # loop over multiple reset codes
             for single_reset_code in re.split(';|\n', reset_code):
                 single_reset_eq = _equation_separator(single_reset_code)
                 on_cond.add_action(
                     lems.StateAssignment(single_reset_eq[0],
                                          single_reset_eq[1]))
         # check event is spike
         spike_flag = False
         if event == 'spike':
             spike_flag = True
         yield (spike_flag, on_cond)
예제 #2
0
 def _event_builder(self, events, event_codes):
     """
     From *events* and *event_codes* yields lems.OnCondition objects
     """
     for ev in events:
         event_out = lems.EventOut(ev)  # output (e.g. spike)
         oc = lems.OnCondition(renderer.render_expr(events[ev]))
         oc.add_action(event_out)
         # if event is not in model ports we should add it
         if ev not in self._component_type.event_ports:
             self._component_type.add(lems.EventPort(name=ev, direction='out'))
         if ev in event_codes:
             for ec in re.split(';|\n', event_codes[ev]):
                 event_eq = _equation_separator(ec)
                 oc.add_action(lems.StateAssignment(event_eq[0], event_eq[1]))
         spike_flag = False
         if ev == SPIKE:
             spike_flag = True
         yield (spike_flag, oc)
def build_lems_for_model(src):
    model = lems.Model()

    model.add(lems.Dimension('time', t=1))
    # model.add(lems.Dimension('au'))

    # primary element of the model is a mass model component
    mass = lems.ComponentType(src.name, extends="baseCellMembPot")
    model.add(mass)
    
    ######### Adding v is required to ease mapping to NEURON...
    mass.dynamics.add(lems.StateVariable(name="v", dimension="voltage", exposure="v"))
    
    mass.add(lems.Attachments(name="synapses",type_="basePointCurrentDL"))
    

    for input in src.input:
        mass.dynamics.add(lems.DerivedVariable(name=input, 
                                               dimension='none',
                                               exposure=input,
                                               select='synapses[*]/I',
                                               reduce='add'))
        mass.add(lems.Exposure(input, 'none'))
        
        
    for key, val in src.const.items():
        mass.add(lems.Parameter(key, 'none'))  # TODO units
        
    
        
    mass.add(lems.Constant(name="MSEC", dimension="time", value="1ms"))
    mass.add(lems.Constant(name="PI", dimension="none", value="3.14159265359"))

    states = []
    der_vars = []
    # for key in src.param:
    #     mass.add(lems.Parameter(key, 'au'))  # TODO units

    for key, val in src.auxex:
        val = val.replace('**', '^')
        mass.dynamics.add(lems.DerivedVariable(key, value=val))

    for key in src.obsrv:
        name_dv = key.replace('(','_').replace(')','').replace(' - ','_min_')
        mass.dynamics.add(lems.DerivedVariable(name_dv, value=key, exposure=name_dv))
        mass.add(lems.Exposure(name_dv, 'none'))

    for src_svar in src.state_space:
        name = src_svar.name
        ddt = src_svar.drift.replace('**', '^')
        mass.dynamics.add(lems.StateVariable(name, 'none', name))
        mass.dynamics.add(lems.TimeDerivative(name, '(%s)/MSEC'%ddt))
        mass.add(lems.Exposure(name, 'none'))
        
    ''' On condition is not need on the model but NeuroML requires its definition -->
            <OnCondition test="r .lt. 0">
                <EventOut port="spike"/>
            </OnCondition>'''
            
    oc = lems.OnCondition(test='v .gt. 0')
    oc.actions.append(lems.EventOut(port='spike'))
    mass.dynamics.add(oc)

    return model
예제 #4
0
    def add_neurongroup(self, neurongrp, index_neurongrp, initializers):
        """
        Add NeuronGroup to self._model
    
        If number of elements is 1 it adds component of that type, if
        it's bigger, the network is created by calling:
        `make_multiinstantiate`.

        Parameters
        ----------
        neurongrp : dict
            Standard dictionary representation of NeuronGroup object
        index_neurongrp : int
            Index of neurongroup in the network
        initializers : list
            List of initializers defined in the network
        """
        # get name of the neurongrp
        component_name = neurongrp['name']
        self._model_namespace["neuronname"] = component_name
        # add BASE_CELL component
        self._component_type = lems.ComponentType(component_name,
                                                  extends=BASE_CELL)
        # get identifiers attached to neurongrp and create special_properties dict
        identifiers = []
        special_properties = {}

        if 'identifiers' in neurongrp:
            identifiers = neurongrp['identifiers']

        for initializer in initializers:
            if 'identifiers' in initializer:
                identifiers.update(initializer['identifiers'])

        for identifier in identifiers.keys():
            special_properties.update({identifier: None})

        # add the identifers as properties of the component
        for param in self._determine_properties(identifiers):
            self._component_type.add(param)
        # common things for every neuron definition
        # TODO: Is this same for custom events too?
        self._component_type.add(lems.EventPort(name='spike', direction='out'))

        # dynamics of the network
        dynamics = lems.Dynamics()
        # get neurongrp equations
        equations = neurongrp['equations']
        # loop over the variables
        initializer_vars = []
        for initializer in initializers:
            if initializer['source'] == neurongrp['name']:
                initializer_vars.append(initializer['variable'])

        for var in equations.keys():

            # determine the dimension
            dimension = _determine_dimension(equations[var]['unit'])
            # add to all_params_unit
            self._all_params_unit[var] = dimension
            # identify diff eqns to add Exposure
            if equations[var]['type'] == 'differential equation':
                state_var = lems.StateVariable(var,
                                               dimension=dimension,
                                               exposure=var)
                self._component_type.add(
                    lems.Exposure(var, dimension=dimension))
                dynamics.add_state_variable(state_var)
            else:
                if var in initializer_vars and 'i' in initializer['value']:
                    self._component_type.add(lems.Property(var, dimension))
                    special_properties[var] = initializer['value']
                    continue
                state_var = lems.StateVariable(var, dimension=dimension)
                dynamics.add_state_variable(state_var)

        # what happens at initialization
        onstart = lems.OnStart()
        # loop over the initializers
        for var in equations.keys():
            if var in (NOT_REFRACTORY, LAST_SPIKE):
                continue
            # check the initializer is connected to this neurongrp
            if var not in initializer_vars:
                continue
            if var in special_properties:
                continue
            for initializer in initializers:
                if initializer['variable'] == var and initializer[
                        'source'] == neurongrp['name']:
                    init_value = initializer['value']
            if type(init_value) != str:
                value = brian_unit_to_lems(init_value)
            else:
                value = renderer.render_expr(str(init_value))
            # add to onstart
            onstart.add(lems.StateAssignment(var, value))
        dynamics.add(onstart)

        # check whether refractoriness is defined
        if ('events' in neurongrp and 'spike' in neurongrp['events']
                and 'refractory' in neurongrp['events']['spike']):
            # if refractoriness, we create separate regimes for integrating
            integr_regime = lems.Regime(INTEGRATING, dynamics,
                                        True)  # True -> initial regime
            # check spike event
            # NOTE: isn't refractory only for spike events?
            for spike_flag, on_cond in self._event_builder(
                    neurongrp['events']):
                if spike_flag:
                    # if spike occured we make transition to refractory regime
                    on_cond.add_action(lems.Transition(REFRACTORY))
                integr_regime.add_event_handler(on_cond)
            # add refractory regime
            refrac_regime = lems.Regime(REFRACTORY, dynamics)
            # make lastspike variable and initialize it
            refrac_regime.add_state_variable(
                lems.StateVariable(LAST_SPIKE, dimension='time'))
            oe = lems.OnEntry()
            oe.add(lems.StateAssignment(LAST_SPIKE, 't'))
            refrac_regime.add(oe)
            # after refractory time we make transition to integrating regime
            refractory_code = neurongrp['events']['spike']['refractory']
            if not _equation_separator(str(refractory_code)):
                # if there is no specific variable given, we assume
                # that this is time condition
                ref_oc = lems.OnCondition('t .gt. ( {0} + {1} )'.format(
                    LAST_SPIKE, brian_unit_to_lems(refractory_code)))
            else:
                ref_oc = lems.OnCondition(
                    renderer.render_expr(refractory_code))
            ref_trans = lems.Transition(INTEGRATING)
            ref_oc.add_action(ref_trans)
            refrac_regime.add_event_handler(ref_oc)
            # identify variables with differential equation
            for var in neurongrp['equations']:
                if neurongrp['equations'][var][
                        'type'] == 'differential equation':
                    diff_var = neurongrp['equations'][var]
                    # get the expression
                    td = lems.TimeDerivative(
                        var, renderer.render_expr(diff_var['expr']))
                    # check flags for UNLESS_REFRACTORY TODO: is this available in 'flags' key?
                    if 'flags' in diff_var:
                        # if unless refratory we add only do integration regime
                        if UNLESS_REFRACTORY in diff_var['flags']:
                            integr_regime.add_time_derivative(td)
                            continue
                    # add time derivative to both regimes
                    integr_regime.add_time_derivative(td)
                    refrac_regime.add_time_derivative(td)
            # add the regimes to dynamics
            dynamics.add_regime(integr_regime)
            dynamics.add_regime(refrac_regime)

        else:
            # adding events directly to dynamics
            for spike_flag, on_cond in self._event_builder(
                    neurongrp['events']):
                dynamics.add_event_handler(on_cond)
            # get variables with diff eqns
            for var in neurongrp['equations']:
                if neurongrp['equations'][var][
                        'type'] == 'differential equation':
                    diff_var = neurongrp['equations'][var]
                    td = lems.TimeDerivative(
                        var, renderer.render_expr(diff_var['expr']))
                    # add to dynamics
                    dynamics.add_time_derivative(td)
        # add dynamics to _component_type
        self._component_type.dynamics = dynamics
        # add _component_type to _model
        self._model.add_component_type(self._component_type)
        # get identifiers
        paramdict = dict()
        for ident_name, ident_value in neurongrp['identifiers'].items():
            paramdict[ident_name] = self._unit_lems_validator(ident_value)
        # if more than one neuron use multiinstantiate
        if neurongrp['N'] == 1:
            self._model.add(
                lems.Component("n{}".format(index_neurongrp), component_name,
                               **paramdict))
        else:
            self.make_multiinstantiate(special_properties, component_name,
                                       paramdict, neurongrp['N'])
예제 #5
0
    def add_neurongroup(self, obj, idx_of_ng, namespace, initializers):
        """
        Adds NeuronGroup object *obj* to self._model.

        If number of elements is 1 it adds component of that type, if
        it's bigger, the network is created by calling:
        `make_multiinstantiate`.

        Parameters
        ----------
        obj : brian2.NeuronGroup
            NeuronGroup object to parse
        idx_of_ng : int
            index of neurongroup
        namespace : dict
            dictionary with all neccassary variables definition
        initializers : dict
            initial values for all model variables
        """
        if hasattr(obj, "namespace") and not obj.namespace:
            obj.namespace = namespace
        self._nr_of_neurons = obj.N  # maybe not the most robust solution
        ct_name = "neuron{}".format(idx_of_ng+1)
        self._model_namespace["neuronname"] = ct_name
        self._component_type = lems.ComponentType(ct_name, extends=BASE_CELL)
        # adding parameters
        special_properties = {}
        for key in obj.namespace.keys():
            special_properties[key] = None
        for param in self._determine_properties(obj.namespace):
            self._component_type.add(param)
        # common things for every neuron definition
        self._component_type.add(lems.EventPort(name='spike', direction='out'))
        # dynamics of the network
        dynamics = lems.Dynamics()
        ng_equations = obj.user_equations
        for var in ng_equations:
            if ng_equations[var].type == DIFFERENTIAL_EQUATION:
                dim_ = _determine_dimension(ng_equations[var].unit)
                sv_ = lems.StateVariable(var, dimension=dim_, exposure=var)
                self._all_params_unit[var] = dim_
                dynamics.add_state_variable(sv_)
                self._component_type.add(lems.Exposure(var, dimension=dim_))
            elif ng_equations[var].type in (PARAMETER, SUBEXPRESSION):
                if var == NOT_REFRACTORY:
                    continue
                dim_ = _determine_dimension(ng_equations[var].unit)
                self._all_params_unit[var] = dim_
                # all initializers contatining iterator need to be assigned
                # as a property
                # i is default iterator in Brian2
                if var in initializers and "i" in get_identifiers(str(initializers[var])):
                    self._component_type.add(lems.Property(var, dim_))
                    special_properties[var] = initializers[var]
                    continue
                sv_ = lems.StateVariable(var, dimension=dim_)
                dynamics.add_state_variable(sv_)
        # what happens at initialization
        onstart = lems.OnStart()
        for var in obj.equations.names:
            if var in (NOT_REFRACTORY, LAST_SPIKE):
                continue
            if var not in initializers:
                continue
            if var in special_properties:
                continue
            init_value = initializers[var]
            if type(init_value) != str:
                init_value = brian_unit_to_lems(init_value)
            else:
                init_value = renderer.render_expr(str(init_value))
            onstart.add(lems.StateAssignment(var, init_value))
        dynamics.add(onstart)

        if obj._refractory:
            # if refractoriness, we create separate regimes
            # - for integrating
            integr_regime = lems.Regime(INTEGRATING, dynamics, True)  # True -> initial regime
            for spike_flag, oc in self._event_builder(obj.events, obj.event_codes):
                if spike_flag:
                    # if spike occured we make transition to refractory regime
                    oc.add_action(lems.Transition(REFRACTORY))
                integr_regime.add_event_handler(oc)
            # - for refractory
            refrac_regime = lems.Regime(REFRACTORY, dynamics)
            # we make lastspike variable and initialize it
            refrac_regime.add_state_variable(lems.StateVariable(LAST_SPIKE, dimension='time'))
            oe = lems.OnEntry()
            oe.add(lems.StateAssignment(LAST_SPIKE, 't'))
            refrac_regime.add(oe)
            # after time spiecified in _refractory we make transition
            # to integrating regime
            if not _equation_separator(str(obj._refractory)):
                # if there is no specific variable given, we assume
                # that this is time condition
                ref_oc = lems.OnCondition('t .gt. ( {0} + {1} )'.format(LAST_SPIKE, brian_unit_to_lems(obj._refractory)))
            else:
                ref_oc = lems.OnCondition(renderer.render_expr(obj._refractory))
            ref_trans = lems.Transition(INTEGRATING)
            ref_oc.add_action(ref_trans)
            refrac_regime.add_event_handler(ref_oc)
            for var in obj.user_equations.diff_eq_names:
                td = lems.TimeDerivative(var, renderer.render_expr(str(ng_equations[var].expr)))
                # if unless refratory we add only do integration regime
                if UNLESS_REFRACTORY in ng_equations[var].flags:
                    integr_regime.add_time_derivative(td)
                    continue
                integr_regime.add_time_derivative(td)
                refrac_regime.add_time_derivative(td)
            dynamics.add_regime(integr_regime)
            dynamics.add_regime(refrac_regime)
        else:
            # here we add events directly to dynamics
            for spike_flag, oc in self._event_builder(obj.events, obj.event_codes):
                dynamics.add_event_handler(oc)
            for var in obj.user_equations.diff_eq_names:
                td = lems.TimeDerivative(var, renderer.render_expr(str(ng_equations[var].expr)))
                dynamics.add_time_derivative(td)

        self._component_type.dynamics = dynamics
        # making componenttype is done so we add it to the model
        self._model.add_component_type(self._component_type)
        obj.namespace.pop("init", None)                # kick out init
        # adding component to the model
        paramdict = dict()
        for param in obj.namespace:
            paramdict[param] = self._unit_lems_validator(obj.namespace[param])
        if obj.N == 1:
            self._model.add(lems.Component("n{}".format(idx_of_ng), ct_name, **paramdict))
        else:
            self.make_multiinstantiate(special_properties, ct_name, paramdict)