Changeset 955
- Timestamp:
- 04/22/11 18:04:21 (13 months ago)
- Location:
- trunk
- Files:
-
- 4 modified
-
examples/nineml_neuron.py (modified) (6 diffs)
-
src/connectors.py (modified) (1 diff)
-
src/neuron/nineml.py (modified) (12 diffs)
-
src/nineml/read.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/examples/nineml_neuron.py
r947 r955 1 """ 2 Example of using a cell type defined in 9ML with pyNN.neuron 3 """ 4 5 1 6 import sys 2 sys.path.append("/home/andrew/dev/nineml_all/trunk/lib9ml/python/examples/AL/") 3 sys.path.append("/home/andrew/dev/nineml_all/trunk/code_generation/nmodl/") 7 from os.path import abspath, realpath, join 8 import nineml 9 root = abspath(join(realpath(nineml.__path__[0]), "../../..")) 10 sys.path.append(join(root, "lib9ml/python/examples/AL")) 11 sys.path.append(join(root, "code_generation/nmodl")) 4 12 leaky_iaf = __import__("leaky_iaf") 5 13 coba_synapse = __import__("coba_synapse") … … 7 15 from pyNN.utility import init_logging 8 16 import pyNN.neuron as sim 17 from copy import deepcopy 9 18 10 19 init_logging(None, debug=True) … … 14 23 leaky_iaf.c1, 15 24 excitatory=coba_synapse.c1, 16 port_map=[('V', 'V'), ('Isyn', 'Isyn')]) 25 inhibitory=deepcopy(coba_synapse.c1), 26 port_map={ 27 'excitatory': [('V', 'V'), ('Isyn', 'Isyn')], 28 'inhibitory': [('V', 'V'), ('Isyn', 'Isyn')] 29 }, 30 weight_variables={ 31 'excitatory': 'q', 32 'inhibitory': 'q' 33 }) 17 34 18 35 parameters = { … … 20 37 'gL': 50.0, 21 38 't_ref': 5.0, 22 'tau': 2.0, 39 'excitatory_tau': 2.0, 40 'inhibitory_tau': 5.0, 41 'excitatory_E': 0.0, 42 'inhibitory_E': -70.0, 23 43 'theta': -50.0, 24 44 'vL': -65.0, … … 26 46 } 27 47 28 #celltype = celltype_cls(parameters)29 #cell = celltype.model(**celltype.parameters)30 31 48 cells = sim.Population(1, celltype_cls, parameters) 32 49 cells.initialize('V', parameters['vL']) 33 50 cells.initialize('t_spike', -1e99) # neuron not refractory at start 51 cells.initialize('regime', 1002) # temporary hack 34 52 35 input = sim.Population( 1, sim.SpikeSourcePoisson, {'rate': 100})53 input = sim.Population(2, sim.SpikeSourcePoisson, {'rate': 100}) 36 54 37 connector = sim.OneToOneConnector(weights=0.1, delays=0.5) 38 conn = sim.Projection(input, cells, connector, target='excitatory') 55 connector = sim.OneToOneConnector(weights=1.0, delays=0.5) 56 conn = [sim.Projection(input[0:1], cells, connector, target='excitatory'), 57 sim.Projection(input[1:2], cells, connector, target='inhibitory')] 39 58 40 59 cells._record('V') 41 cells._record('g') 60 cells._record('excitatory_g') 61 cells._record('inhibitory_g') 42 62 cells.record() 43 63 … … 45 65 46 66 cells.recorders['V'].write("Results/nineml_neuron.V", filter=[cells[0]]) 47 cells.recorders['g'].write("Results/nineml_neuron.g", filter=[cells[0]]) 67 cells.recorders['excitatory_g'].write("Results/nineml_neuron.g_exc", filter=[cells[0]]) 68 cells.recorders['inhibitory_g'].write("Results/nineml_neuron.g_inh", filter=[cells[0]]) 48 69 49 70 sim.end() -
trunk/src/connectors.py
r954 r955 442 442 `weights` -- may either be a float, a RandomDistribution object, a list/ 443 443 1D array with at least as many items as connections to be 444 created, or a DistanceDependence object. Units nA.444 created, or a distance expression as for `d_expression`. Units nA. 445 445 `delays` -- as `weights`. If `None`, all synaptic delays will be set 446 446 to the global minimum delay. -
trunk/src/neuron/nineml.py
r950 r955 1 ## Not compatible with Python 2.4 ### 2 from __future__ import absolute_import 1 """ 2 Support cell types defined in 9ML with NEURON. 3 4 Requires the 9ml2nmodl script to be on the path. 5 6 Classes: 7 NineMLCell - a single neuron instance 8 NineMLCellType - base class for cell types, not used directly 9 10 Functions: 11 nineml_cell_type - return a new NineMLCellType subclass 12 13 Constants: 14 NMODL_DIR - subdirectory to which NMODL mechanisms will be written 15 16 """ 17 18 from __future__ import absolute_import # Not compatible with Python 2.4 3 19 import subprocess 4 20 import neuron … … 7 23 import logging 8 24 import os 25 import re 9 26 from itertools import chain 10 27 … … 60 77 61 78 62 def _compile_nmodl(nineml_component): 79 def _compile_nmodl(nineml_component, weight_variables): # weight variables should really be within component 80 """ 81 Generate NMODL code for the 9ML component, run "nrnivmodl" and then load 82 the mechanisms into NEURON. 83 """ 63 84 if not os.path.exists(NMODL_DIR): 64 85 os.makedirs(NMODL_DIR) … … 69 90 nineml_component.write(xml_file) 70 91 nineml2nmodl = __import__("9ml2nmodl") 71 nineml2nmodl.write_nmodl(xml_file )92 nineml2nmodl.write_nmodl(xml_file, weight_variables) # weight variables should really come from xml file 72 93 p = subprocess.check_call(["nrnivmodl"]) 73 94 os.chdir(cwd) … … 75 96 76 97 98 def _add_prefix(synapse_model, prefix, port_map): 99 """ 100 Add a prefix to all variables in `synapse_model`, except for variables with 101 receive ports and specified in `port_map`. 102 """ 103 synapse_model.__cache__ = {} 104 exclude = [] 105 new_port_map = [] 106 for name1, name2 in port_map: 107 if synapse_model.ports_map[name2].mode == 'recv': 108 exclude.append(name2) 109 new_port_map.append((name1, name2)) 110 else: 111 new_port_map.append((name1, prefix + '_' + name2)) 112 synapse_model.add_prefix(prefix + '_', exclude=exclude) 113 return new_port_map 114 115 77 116 class _build_nineml_celltype(type): 78 117 """ … … 80 119 """ 81 120 def __new__(cls, name, bases, dct): 82 assert len(dct["synapse_models"]) == 1, "For now, can't handle multiple synapse models" 83 combined_model = join(dct["neuron_model"], 84 dct["synapse_models"].values()[0], 85 dct["port_map"], 86 name=name) 121 # join the neuron and synapse components into a single component 122 combined_model = dct["neuron_model"] 123 for label in dct["synapse_models"].keys(): 124 port_map = dct["port_map"][label] 125 port_map = _add_prefix(dct["synapse_models"][label], label, port_map) 126 dct["weight_variables"][label] = label + "_" + dct["weight_variables"][label] 127 combined_model = join(combined_model, 128 dct["synapse_models"][label], 129 port_map, 130 name=name) 87 131 dct["combined_model"] = combined_model 132 # set class attributes required for a PyNN cell type class 88 133 dct["default_parameters"] = dict((name, 1.0) 89 134 for name in combined_model.parameters) … … 92 137 dct["synapse_types"] = dct["synapse_models"].keys() #really need an ordered dict 93 138 dct["injectable"] = True # need to determine this. How?? 94 dct["recordable"] = [port.name for port in combined_model.analog_ports] + ['spikes' ]139 dct["recordable"] = [port.name for port in combined_model.analog_ports] + ['spikes', 'regime'] 95 140 dct["standard_receptor_type"] = (dct["synapse_types"] == ('excitatory', 'inhibitory')) 96 141 dct["conductance_based"] = True # how to determine this?? 97 142 dct["model_name"] = name 98 143 logger.debug("Creating class '%s' with bases %s and dictionary %s" % (name, bases, dct)) 99 _compile_nmodl(combined_model) 144 # generate and compile NMODL code, then load the mechanism into NEUORN 145 _compile_nmodl(combined_model, dct["weight_variables"]) # weight variables should really be stored within combined_model 100 146 return type.__new__(cls, name, bases, dct) 101 147 102 148 103 149 104 def nineml_cell_type(name, neuron_model, port_map={}, **synapse_models):150 def nineml_cell_type(name, neuron_model, port_map={}, weight_variables={}, **synapse_models): 105 151 """ 106 152 Return a new NineMLCellType subclass. … … 109 155 {'neuron_model': neuron_model, 110 156 'synapse_models': synapse_models, 111 'port_map': port_map}) 112 157 'port_map': port_map, 158 'weight_variables': weight_variables}) 159 113 160 114 161 def join(c1, c2, port_map=[], name=None): … … 116 163 logger.debug("Joining components %s and %s with port map %s" % (c1, c2, port_map)) 117 164 logger.debug("New component will have name '%s'" % name) 118 bindings = [] # TODO: combine bindings from c1 and c2 165 # combine bindings from c1 and c2 166 bindings = {} 167 for b in chain(c1.bindings, c2.bindings): 168 bindings[b.name] = b 169 # combine ports (some will later be removed) 119 170 all_ports = c1.ports_map.copy() 120 171 all_ports.update(c2.ports_map) 172 # event ports do not be passed to the constructor, as they are attached to transitions 121 173 for port_name, port in all_ports.items(): 122 174 if isinstance(port, nineml.EventPort): 123 175 all_ports.pop(port_name) 176 # connect ports. 177 # currently, when ports are connected they disappear. It might be better to 178 # explicitly keep the ports in the new component but mark them as connected 124 179 for name1, name2 in port_map: 125 assert name1 in c1.ports_map 126 assert name2 in c2.ports_map 127 all_ports.pop(name1) 128 if name1 != name2: 129 #c2.substitute(name2, name1) # need to implement this 130 all_ports.pop(name2) 131 180 assert name1 in c1.ports_map, "%s is not in %s" % (name1, c1.ports_map.keys()) 181 assert name2 in c2.ports_map, "%s is not in %s" % (name2, c2.ports_map.keys()) 182 132 183 port1 = c1.ports_map[name1] 133 184 port2 = c2.ports_map[name2] … … 135 186 if port1.mode == 'send': 136 187 send_port = port1 137 port_name = name1 188 recv_port = port2 189 send_port_name = name1 190 recv_port_name = name2 138 191 else: 139 192 send_port = port2 140 port_name = name2 193 recv_port = port1 194 send_port_name = name2 195 recv_port_name = name1 196 # when connecting ports in which the send port has an expression, need 197 # to create a binding for this expression in the new component 141 198 if send_port.expr: 142 199 func_args = c1.non_parameter_symbols.union(c2.non_parameter_symbols).intersection(send_port.expr.names) 143 lhs = "%s(%s)" % (port_name, ",".join(func_args)) 144 bindings.append(nineml.Binding(lhs, send_port.expr.rhs)) 200 lhs = "%s(%s)" % (send_port_name, ",".join(func_args)) 201 send_binding = nineml.Binding(lhs, send_port.expr.rhs) 202 bindings[send_binding.name] = send_binding 145 203 for eq in chain(c1.equations, c2.equations): 146 if port_name in eq.names: 147 eq.rhs = eq.rhs_name_transform({port_name: lhs}) 204 if send_port_name in eq.names: 205 eq.rhs = eq.rhs_name_transform({send_port_name: lhs}) 206 if recv_port.mode == 'reduce': 207 # need to retain reduce ports as they can be connected to in a future join 208 if recv_port_name in bindings: 209 # this reduce port has already been connected to, so combine using its reduce_op 210 reduce_binding = bindings[recv_port_name] 211 func_args = func_args.union(reduce_binding.args) 212 lhs = "%s(%s)" % (recv_port_name, ",".join(func_args)) 213 rhs = recv_port.reduce_op.join([reduce_binding.rhs, send_binding.lhs]) 214 else: 215 # this is the first time this reduce port has been connected to 216 lhs = "%s(%s)" % (recv_port_name, ",".join(func_args)) 217 rhs = send_binding.lhs 218 bindings[recv_port_name] = nineml.Binding(lhs, rhs) 219 recv_port.connected = True 220 else: 221 all_ports.pop(name1) 222 else: 223 if recv_port.mode == 'reduce': 224 raise NotImplementedError 225 else: 226 all_ports.pop(name1) 227 228 if name1 != name2: 229 #c2.substitute(name2, name1) # need to implement this. Currently this all only works if name1 == name2 230 # probably needs to happen sooner in the function 231 all_ports.pop(name2) 232 233 # where parameters have become bindings due to connecting ports, replace 234 # bare names with function calls in the equations 235 for bname, binding in bindings.items(): 236 for eq in chain(c1.equations, c2.equations): 237 if bname in eq.names: 238 print "#### replacing %s by %s" % (bname, binding.lhs) 239 pattern = re.compile(r'%s(\([\w\, ]*\))?' % bname) 240 m = pattern.search(eq.rhs) 241 if m: 242 eq.rhs = pattern.sub(binding.lhs, eq.rhs) 243 else: 244 eq.rhs = eq.rhs_name_transform({bname: binding.lhs}) 245 246 # create new regimes from all possible combinations of the regimes from the 247 # two components 148 248 regime_map = {} 149 249 for r1 in c1.regimes: 150 250 regime_map[r1.name] = {} 151 251 for r2 in c2.regimes: 152 kwargs = {'name': "%s_AND_%s" % (r1.name, r2.name)} 252 if r1.name == r2.name: 253 new_name = r1.name 254 else: 255 new_name = "%s_AND_%s" % (r1.name, r2.name) 256 kwargs = {'name': new_name} 153 257 new_regime = nineml.Regime(*r1.nodes.union(r2.nodes), **kwargs) 154 258 regime_map[r1.name][r2.name] = new_regime 259 # create transitions between all the new regimes 155 260 transitions = [] 156 261 for r1 in c1.regimes: … … 168 273 condition=t.condition) 169 274 transitions.append(new_transition) 275 170 276 regimes = [] 171 277 for d in regime_map.values(): … … 176 282 transitions=transitions, 177 283 ports=all_ports.values(), 178 bindings=bindings )284 bindings=bindings.values()) -
trunk/src/nineml/read.py
r790 r955 188 188 """ 189 189 190 def __init__(self, sim, nineml_ file):190 def __init__(self, sim, nineml_model): 191 191 """ 192 192 Instantiate a network from a 9ML file, in the specified simulator. 193 193 """ 194 194 global random_distributions 195 assert isinstance(nineml_file, basestring)196 195 self.sim = sim 197 self.nineml_model = nineml.parse(nineml_file) 196 if isinstance(nineml_model, basestring): 197 self.nineml_model = nineml.parse(nineml_model) 198 elif isinstance(nineml_model, nineml.Model): 199 self.nineml_model = nineml_model 200 else: 201 raise TypeError("nineml_model must be a nineml.Model instance or the path to a NineML XML file.") 198 202 self.random_distributions = {} 199 203 self.assemblies = {} … … 207 211 def _handle_group(self, group): 208 212 # create an Assembly 209 self.assemblies[group.name] = self.sim.Assembly( group.name)213 self.assemblies[group.name] = self.sim.Assembly(label=group.name) 210 214 211 215 # extract post-synaptic response definitions from projections
