def make_multiinstantiate(self, special_properties, name, parameters): """ Adds ComponentType with MultiInstantiate in order to make a population of neurons. Parameters ---------- special_properties : dict all variables to be defined in MultiInstantiate name : str MultiInstantiate component name parameters : dict all extra parameters needed """ PARAM_SUBSCRIPT = "_p" self._model_namespace["ct_populationname"] = name+"Multi" multi_ct = lems.ComponentType(self._model_namespace["ct_populationname"], extends=BASE_POPULATION) structure = lems.Structure() multi_ins = lems.MultiInstantiate(component_type=name, number="N") param_dict = {} # number of neruons multi_ct.add(lems.Parameter(name="N", dimension="none")) # other parameters for sp in special_properties: if special_properties[sp] is None: multi_ct.add(lems.Parameter(name=sp+PARAM_SUBSCRIPT, dimension=self._all_params_unit[sp])) multi_ins.add(lems.Assign(property=sp, value=sp+PARAM_SUBSCRIPT)) param_dict[sp] = parameters[sp] else: # multi_ct.add(lems.Parameter(name=sp, dimension=self._all_params_unit[sp])) # check if there are some units in equations equation = special_properties[sp] # add spaces around brackets to prevent mismatching equation = re.sub("\(", " ( ", equation) equation = re.sub("\)", " ) ", equation) for i in get_identifiers(equation): # iterator is a special case if i == "i": regexp_noletter = "[^a-zA-Z0-9]" equation = re.sub("{re}i{re}".format(re=regexp_noletter), " {} ".format(INDEX), equation) # here it's assumed that we don't use Netwton in neuron models elif i in name_to_unit and i != "N": const_i = i+'const' multi_ct.add(lems.Constant(name=const_i, symbol=const_i, dimension=self._all_params_unit[sp], value="1"+i)) equation = re.sub(i, const_i, equation) multi_ins.add(lems.Assign(property=sp, value=equation)) structure.add(multi_ins) multi_ct.structure = structure self._model.add(multi_ct) param_dict = dict([(k+"_p", v) for k, v in param_dict.items()]) param_dict["N"] = self._nr_of_neurons self._model_namespace["populationname"] = self._model_namespace["ct_populationname"] + "pop" self._model_namespace["networkname"] = self._model_namespace["ct_populationname"] + "Net" self.add_population(self._model_namespace["networkname"], self._model_namespace["populationname"], self._model_namespace["ct_populationname"], **param_dict)
def add_synapses(self, obj): """ TO DO - not ready to use Adds synapses to the model. Parameters ---------- obj : brian2.Synapse Synapse object """ synapse_ct = lems.ComponentType('Synapse') dynamics_synapse = lems.Dynamics() synapse_ct.add(dynamics_synapse)
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
#! /usr/bin/python import lems.api as lems model = lems.Model() model.add(lems.Dimension('voltage', m=1, l=3, t=-3, i=-1)) model.add(lems.Dimension('time', t=1)) model.add(lems.Dimension('capacitance', m=-1, l=-2, t=4, i=2)) model.add(lems.Unit('milliVolt', 'mV', 'voltage', -3)) model.add(lems.Unit('milliSecond', 'ms', 'time', -3)) model.add(lems.Unit('microFarad', 'uF', 'capacitance', -12)) iaf1 = lems.ComponentType('iaf1') model.add(iaf1) iaf1.add(lems.Parameter('threshold', 'voltage')) iaf1.add(lems.Parameter('reset', 'voltage')) iaf1.add(lems.Parameter('refractoryPeriod', 'time')) iaf1.add(lems.Parameter('capacitance', 'capacitance')) iaf1.add(lems.Exposure('vexp', 'voltage')) dp = lems.DerivedParameter('range', 'threshold - reset', 'voltage') iaf1.add(dp) iaf1.dynamics.add(lems.StateVariable('v','voltage', 'vexp')) iaf1.dynamics.add(lems.DerivedVariable('v2',dimension='voltage', value='v*2')) cdv = lems.ConditionalDerivedVariable('v_abs','voltage') cdv.add(lems.Case('v .geq. 0','v')) cdv.add(lems.Case('v .lt. 0','-1*v')) iaf1.dynamics.add(cdv)
def channelpedia_xml_to_neuroml2(cpd_xml, nml2_file_name, unknowns=""): info = 'Automatic conversion of Channelpedia XML file to NeuroML2\n'+\ 'Uses: https://github.com/OpenSourceBrain/BlueBrainProjectShowcase/blob/master/Channelpedia/ChannelpediaToNeuroML2.py' print(info) root = ET.fromstring(cpd_xml) channel_id = 'Channelpedia_%s_%s' % (root.attrib['ModelName'].replace( "/", "_").replace(" ", "_").replace(".", "_"), root.attrib['ModelID']) doc = neuroml.NeuroMLDocument() metadata = osb.metadata.RDF(info) ion = root.findall('Ion')[0] chan = neuroml.IonChannelHH( id=channel_id, conductance='10pS', species=ion.attrib['Name'], notes= "This is an automated conversion to NeuroML 2 of an ion channel model from Channelpedia. " + "\nThe original channel model file can be found at: http://channelpedia.epfl.ch/ionchannels/%s" % root.attrib['ID'] + "\n\nConversion scripts at https://github.com/OpenSourceBrain/BlueBrainProjectShowcase" ) chan.annotation = neuroml.Annotation() model_url_template = 'http://channelpedia.epfl.ch/ionchannels/%s/hhmodels/%s.xml' desc = osb.metadata.Description(channel_id) metadata.descriptions.append(desc) osb.metadata.add_simple_qualifier(desc, \ 'bqmodel', \ 'isDerivedFrom', \ model_url_template%(root.attrib['ID'], root.attrib['ModelID']), \ "Channelpedia channel ID: %s, ModelID: %s; direct link to original XML model" % (root.attrib['ID'], root.attrib['ModelID'])) channel_url_template = 'http://channelpedia.epfl.ch/ionchannels/%s' osb.metadata.add_simple_qualifier(desc, \ 'bqmodel', \ 'isDescribedBy', \ channel_url_template%(root.attrib['ID']), \ "Channelpedia channel ID: %s; link to main page for channel" % (root.attrib['ID'])) for reference in root.findall('Reference'): pmid = reference.attrib['PubmedID'] #metadata = update_metadata(chan, metadata, channel_id, "http://identifiers.org/pubmed/%s"%pmid) ref_info = reference.text osb.metadata.add_simple_qualifier(desc, \ 'bqmodel', \ 'isDescribedBy', \ osb.resources.PUBMED_URL_TEMPLATE % (pmid), \ ("PubMed ID: %s is referenced in original XML\n"+\ " %s") % (pmid, ref_info)) for environment in root.findall('Environment'): for animal in environment.findall('Animal'): species = animal.attrib['Name'].lower() if species: if species in osb.resources.KNOWN_SPECIES: known_id = osb.resources.KNOWN_SPECIES[species] osb.metadata.add_simple_qualifier(desc, \ 'bqbiol', \ 'hasTaxon', \ osb.resources.NCBI_TAXONOMY_URL_TEMPLATE % known_id, \ "Known species: %s; taxonomy id: %s" % (species, known_id)) else: print("Unknown species: %s" % species) unknowns += "Unknown species: %s\n" % species for cell_type_el in environment.findall('CellType'): cell_type = cell_type_el.text.strip().lower() if cell_type: if cell_type in osb.resources.KNOWN_CELL_TYPES: known_id = osb.resources.KNOWN_CELL_TYPES[cell_type] osb.metadata.add_simple_qualifier(desc, \ 'bqbiol', \ 'isPartOf', \ osb.resources.NEUROLEX_URL_TEMPLATE % known_id, \ "Known cell type: %s; taxonomy id: %s" % (cell_type, known_id)) else: print("Unknown cell_type: %s" % cell_type) unknowns += "Unknown cell_type: %s\n" % cell_type print("Currently unknown: <<<%s>>>" % unknowns) comp_types = {} for gate in root.findall('Gates'): eq_type = gate.attrib['EqType'] gate_name = gate.attrib['Name'] target = chan.gates if eq_type == '1': g = neuroml.GateHHUndetermined(id=gate_name, type='gateHHtauInf', instances=int( float(gate.attrib['Power']))) elif eq_type == '2': g = neuroml.GateHHUndetermined(id=gate_name, type='gateHHrates', instances=int( float(gate.attrib['Power']))) for inf in gate.findall('Inf_Alpha'): equation = check_equation(inf.findall('Equation')[0].text) if eq_type == '1': new_comp_type = "%s_%s_%s" % (channel_id, gate_name, 'inf') g.steady_state = neuroml.HHVariable(type=new_comp_type) comp_type = lems.ComponentType( new_comp_type, extends="baseVoltageDepVariable") comp_type.add(lems.Constant('TIME_SCALE', '1 ms', 'time')) comp_type.add(lems.Constant('VOLT_SCALE', '1 mV', 'voltage')) comp_type.dynamics.add( lems.DerivedVariable(name='V', dimension="none", value="v / VOLT_SCALE")) comp_type.dynamics.add( lems.DerivedVariable(name='x', dimension="none", value="%s" % equation, exposure="x")) comp_types[new_comp_type] = comp_type elif eq_type == '2': new_comp_type = "%s_%s_%s" % (channel_id, gate_name, 'alpha') g.forward_rate = neuroml.HHRate(type=new_comp_type) comp_type = lems.ComponentType(new_comp_type, extends="baseVoltageDepRate") comp_type.add(lems.Constant('TIME_SCALE', '1 ms', 'time')) comp_type.add(lems.Constant('VOLT_SCALE', '1 mV', 'voltage')) comp_type.dynamics.add( lems.DerivedVariable(name='V', dimension="none", value="v / VOLT_SCALE")) comp_type.dynamics.add( lems.DerivedVariable(name='r', dimension="per_time", value="%s / TIME_SCALE" % equation, exposure="r")) comp_types[new_comp_type] = comp_type for tau in gate.findall('Tau_Beta'): equation = check_equation(tau.findall('Equation')[0].text) if eq_type == '1': new_comp_type = "%s_%s_tau" % (channel_id, gate_name) g.time_course = neuroml.HHTime(type=new_comp_type) comp_type = lems.ComponentType(new_comp_type, extends="baseVoltageDepTime") comp_type.add(lems.Constant('TIME_SCALE', '1 ms', 'time')) comp_type.add(lems.Constant('VOLT_SCALE', '1 mV', 'voltage')) comp_type.dynamics.add( lems.DerivedVariable(name='V', dimension="none", value="v / VOLT_SCALE")) comp_type.dynamics.add( lems.DerivedVariable(name='t', dimension="time", value="(%s) * TIME_SCALE" % equation, exposure="t")) comp_types[new_comp_type] = comp_type elif eq_type == '2': new_comp_type = "%s_%s_%s" % (channel_id, gate_name, 'beta') g.reverse_rate = neuroml.HHRate(type=new_comp_type) comp_type = lems.ComponentType(new_comp_type, extends="baseVoltageDepRate") comp_type.add(lems.Constant('TIME_SCALE', '1 ms', 'time')) comp_type.add(lems.Constant('VOLT_SCALE', '1 mV', 'voltage')) comp_type.dynamics.add( lems.DerivedVariable(name='V', dimension="none", value="v / VOLT_SCALE")) comp_type.dynamics.add( lems.DerivedVariable(name='r', dimension="per_time", value="%s / TIME_SCALE" % equation, exposure="r")) comp_types[new_comp_type] = comp_type target.append(g) doc.ion_channel_hhs.append(chan) doc.id = channel_id writers.NeuroMLWriter.write(doc, nml2_file_name) print("Written NeuroML 2 channel file to: " + nml2_file_name) for comp_type_name in comp_types.keys(): comp_type = comp_types[comp_type_name] ct_xml = comp_type.toxml() # Quick & dirty pretty printing.. ct_xml = ct_xml.replace('<Const', '\n <Const') ct_xml = ct_xml.replace('<Dyna', '\n <Dyna') ct_xml = ct_xml.replace('</Dyna', '\n </Dyna') ct_xml = ct_xml.replace('<Deriv', '\n <Deriv') ct_xml = ct_xml.replace('</Compone', '\n </Compone') # print("Adding definition for %s:\n%s\n"%(comp_type_name, ct_xml)) nml2_file = open(nml2_file_name, 'r') orig = nml2_file.read() new_contents = orig.replace("</neuroml>", "\n %s\n\n</neuroml>" % ct_xml) nml2_file.close() nml2_file = open(nml2_file_name, 'w') nml2_file.write(new_contents) nml2_file.close() print("Inserting metadata...") nml2_file = open(nml2_file_name, 'r') orig = nml2_file.read() new_contents = orig.replace( "<annotation/>", "\n <annotation>\n%s </annotation>\n" % metadata.to_xml(" ")) nml2_file.close() nml2_file = open(nml2_file_name, 'w') nml2_file.write(new_contents) nml2_file.close() ###### Validate the NeuroML ###### from neuroml.utils import validate_neuroml2 validate_neuroml2(nml2_file_name) return unknowns
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'])
#!/usr/bin/env python3 import lems.api as lems from lems.base.util import validate_lems model = lems.Model() model.add(lems.Dimension(name="time", t=1)) model.add(lems.Unit(name="second", symbol="s", dimension="time", power=1)) model.add( lems.Unit(name="milli second", symbol="ms", dimension="time", power=-3)) lorenz = lems.ComponentType( name="lorenz1963", description= "The Lorenz system is a simplified model for atomspheric convection, derived from the Navier Stokes equations" ) model.add(lorenz) lorenz.add( lems.Parameter(name="sigma", dimension="none", description="Prandtl Number")) lorenz.add( lems.Parameter(name="beta", dimension="none", description="Also named b elsewhere")) lorenz.add( lems.Parameter( name="rho", dimension="none",
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)
def mdf_to_neuroml(graph, save_to=None, format=None, run_duration_sec=2): print("Converting graph: %s to NeuroML" % (graph.id)) net = neuromllite.Network(id=graph.id) net.notes = "NeuroMLlite export of {} graph: {}".format( format if format else "MDF", graph.id, ) model = lems.Model() lems_definitions = "%s_lems_definitions.xml" % graph.id for node in graph.nodes: print(" Node: %s" % node.id) node_comp_type = "%s__definition" % node.id node_comp = "%s__instance" % node.id # Create the ComponentType which defines behaviour of the general class ct = lems.ComponentType(node_comp_type, extends="baseCellMembPotDL") ct.add(lems.Attachments("only_input_port", "basePointCurrentDL")) ct.dynamics.add( lems.DerivedVariable(name="V", dimension="none", value="0", exposure="V")) model.add(ct) # Define the Component - an instance of the ComponentType comp = lems.Component(node_comp, node_comp_type) model.add(comp) cell = neuromllite.Cell(id=node_comp, lems_source_file=lems_definitions) net.cells.append(cell) pop = neuromllite.Population( id=node.id, size=1, component=cell.id, properties={ "color": "0.2 0.2 0.2", "radius": 3 }, ) net.populations.append(pop) if len(node.input_ports) > 1: raise Exception( "Currently only max 1 input port supported in NeuroML...") for ip in node.input_ports: ct.add(lems.Exposure(ip.id, "none")) ct.dynamics.add( lems.DerivedVariable( name=ip.id, dimension="none", select="only_input_port[*]/I", reduce="add", exposure=ip.id, )) on_start = None for p in node.parameters: print("Converting %s" % p) if p.value is not None: try: v_num = float(p.value) ct.add(lems.Parameter(p.id, "none")) comp.parameters[p.id] = v_num print(comp.parameters[p.id]) except Exception as e: ct.add(lems.Exposure(p.id, "none")) dv = lems.DerivedVariable( name=p.id, dimension="none", value="%s" % (p.value), exposure=p.id, ) ct.dynamics.add(dv) elif p.function is not None: ct.add(lems.Exposure(p.id, "none")) func_info = mdf_functions[p.function] expr = func_info["expression_string"] expr2 = substitute_args(expr, p.args) for arg in p.args: expr += ";{}={}".format(arg, p.args[arg]) dv = lems.DerivedVariable(name=p.id, dimension="none", value="%s" % (expr2), exposure=p.id) ct.dynamics.add(dv) else: ct.add(lems.Exposure(p.id, "none")) ct.dynamics.add( lems.StateVariable(name=p.id, dimension="none", exposure=p.id)) if p.default_initial_value: if on_start is None: on_start = lems.OnStart() ct.dynamics.add(on_start) sa = lems.StateAssignment( variable=p.id, value=str(evaluate_expr(p.default_initial_value))) on_start.actions.append(sa) if p.time_derivative: td = lems.TimeDerivative(variable=p.id, value=p.time_derivative) ct.dynamics.add(td) if len(node.output_ports) > 1: raise Exception( "Currently only max 1 output port supported in NeuroML...") for op in node.output_ports: ct.add(lems.Exposure(op.id, "none")) ct.dynamics.add( lems.DerivedVariable(name=op.id, dimension="none", value=op.value, exposure=op.id)) only_output_port = "only_output_port" ct.add(lems.Exposure(only_output_port, "none")) ct.dynamics.add( lems.DerivedVariable( name=only_output_port, dimension="none", value=op.id, exposure=only_output_port, )) if len(graph.edges) > 0: model.add( lems.Include( os.path.join(os.path.dirname(__file__), "syn_definitions.xml"))) rsDL = neuromllite.Synapse(id="rsDL", lems_source_file=lems_definitions) net.synapses.append(rsDL) # syn_id = 'silentSyn' # silentSynDL = neuromllite.Synapse(id=syn_id, lems_source_file=lems_definitions) for edge in graph.edges: print(f" Edge: {edge.id} connects {edge.sender} to {edge.receiver}") ssyn_id = "silentSyn_proj_%s" % edge.id ssyn_id = "silentSyn_proj_%s" % edge.id # ssyn_id = 'silentSynX' silentDLin = neuromllite.Synapse(id=ssyn_id, lems_source_file=lems_definitions) model.add(lems.Component(ssyn_id, "silentRateSynapseDL")) net.synapses.append(silentDLin) net.projections.append( neuromllite.Projection( id="proj_%s" % edge.id, presynaptic=edge.sender, postsynaptic=edge.receiver, synapse=rsDL.id, pre_synapse=silentDLin.id, type="continuousProjection", weight=1, random_connectivity=neuromllite.RandomConnectivity( probability=1), )) # Much more todo... model.export_to_file(lems_definitions) print("Nml net: %s" % net) if save_to: new_file = net.to_json_file(save_to) print("Saved NML to: %s" % save_to) ################################################################################ ### Build Simulation object & save as JSON simtime = 1000 * run_duration_sec dt = 0.1 sim = neuromllite.Simulation( id="Sim%s" % net.id, network=new_file, duration=simtime, dt=dt, seed=123, recordVariables={"OUTPUT": { "all": "*" }}, ) recordVariables = {} for node in graph.nodes: for ip in node.input_ports: if not ip.id in recordVariables: recordVariables[ip.id] = {} recordVariables[ip.id][node.id] = 0 for p in node.parameters: if p.is_stateful(): if not p.id in recordVariables: recordVariables[p.id] = {} recordVariables[p.id][node.id] = 0 for op in node.output_ports: if not op.id in recordVariables: recordVariables[op.id] = {} recordVariables[op.id][node.id] = 0 sim.recordVariables = recordVariables if save_to: sf = sim.to_json_file() print("Saved Simulation to: %s" % sf) return net, sim