def printNetTree(): """ Prints all the cells under /, and recursive prints the cell tree for each cell. """ root = _moose.Neutral('/') for id in root.children: # all subelements of 'root' if _moose.Neutral(id).className == 'Cell': cell = _moose.Cell(id) print "-------------------- CELL : ", cell.name, " ---------------------------" printCellTree(cell)
def setupTable(name, obj, qtyname, tables_path=None, threshold=None, spikegen=None): """ Sets up a table with 'name' which stores 'qtyname' field from 'obj'. The table is created under tables_path if not None, else under obj.path . """ if tables_path is None: tables_path = obj.path + '/data' ## in case tables_path does not exist, below wrapper will create it tables_path_obj = _moose.Neutral(tables_path) qtyTable = _moose.Table(tables_path_obj.path + '/' + name) ## stepMode no longer supported, connect to 'input'/'spike' message dest to record Vm/spiktimes # qtyTable.stepMode = TAB_BUF if spikegen is None: if threshold is None: ## below is wrong! reads qty twice every clock tick! #_moose.connect( obj, qtyname+'Out', qtyTable, "input") ## this is the correct method _moose.connect(qtyTable, "requestOut", obj, 'get' + qtyname) else: ## create new spikegen spikegen = _moose.SpikeGen(tables_path_obj.path + '/' + name + '_spikegen') ## connect the compartment Vm to the spikegen _moose.connect(obj, "VmOut", spikegen, "Vm") ## spikegens for different synapse_types can have different thresholds spikegen.threshold = threshold spikegen.edgeTriggered = 1 # This ensures that spike is generated only on leading edge. else: _moose.connect(spikegen, 'spikeOut', qtyTable, 'input') ## spikeGen gives spiketimes return qtyTable
def get_matching_children(parent, names): """ Returns non-recursive children of 'parent' MOOSE object with their names containing any of the strings in list 'names'. """ matchlist = [] for childID in parent.children: child = _moose.Neutral(childID) for name in names: if name in child.name: matchlist.append(childID) return matchlist
def df_traverse(root, operation, *args): """Traverse the tree in a depth-first manner and apply the operation using *args. The first argument is the root object by default.""" if hasattr(root, '_visited'): return operation(root, *args) for child in root.children: childNode = _moose.Neutral(child) df_traverse(childNode, operation, *args) root._visited = True
def main(): _moose.Neutral('/cable') c1 = _moose.Compartment('/cable/a') c2 = _moose.Compartment('/cable/b') c1.connect('raxial', c2, 'axial') p = _moose.PulseGen('/pulse1') p.delay[0] = 0.01 p.level[0] = 1e-9 p.width[0] = 0.10 p.delay[1] = 0.08 p.connect('output', c1, 'injectMsg') s = Spice() print s.writeSpice(output='test_spice.spice')
def printRecursiveTree(elementid, level): """ Recursive helper function for printCellTree, specify depth/'level' to recurse and print subelements under MOOSE 'elementid'. """ spacefill = ' ' * level element = _moose.Neutral(elementid) for childid in element.children: childobj = _moose.Neutral(childid) classname = childobj.className if classname in ['SynChan', 'KinSynChan']: childobj = _moose.SynChan(childid) print spacefill + "|--", childobj.name, childobj.className, 'Gbar=', childobj.Gbar, 'numSynapses=', childobj.numSynapses return # Have yet to figure out the children of SynChan, currently not going deeper elif classname in ['HHChannel', 'HHChannel2D']: childobj = _moose.HHChannel(childid) print spacefill + "|--", childobj.name, childobj.className, 'Gbar=', childobj.Gbar, 'Ek=', childobj.Ek elif classname in ['CaConc']: childobj = _moose.CaConc(childid) print spacefill + "|--", childobj.name, childobj.className, 'thick=', childobj.thick, 'B=', childobj.B elif classname in ['Mg_block']: childobj = _moose.Mg_block(childid) print spacefill + "|--", childobj.name, childobj.className, 'CMg', childobj.CMg, 'KMg_A', childobj.KMg_A, 'KMg_B', childobj.KMg_B elif classname in ['SpikeGen']: childobj = _moose.SpikeGen(childid) print spacefill + "|--", childobj.name, childobj.className, 'threshold', childobj.threshold elif classname in ['Func']: childobj = _moose.Func(childid) print spacefill + "|--", childobj.name, childobj.className, 'expr', childobj.expr elif classname in [ 'Table' ]: # Table gives segfault if printRecursiveTree is called on it return # so go no deeper #for inmsg in childobj.inMessages(): # print spacefill+" |---", inmsg #for outmsg in childobj.outMessages(): # print spacefill+" |---", outmsg if len(childobj.children) > 0: printRecursiveTree(childid, level + 1)
def blockChannels(cell, channel_list): """ Sets gmax to zero for channels of the 'cell' specified in 'channel_list' Substring matches in channel_list are allowed e.g. 'K' should block all K channels (ensure that you don't use capital K elsewhere in your channel name!) """ for compartmentid in cell.children: # compartments comp = _moose.Compartment(compartmentid) for childid in comp.children: child = _moose.Neutral(childid) if child.className in ['HHChannel', 'HHChannel2D']: chan = _moose.HHChannel(childid) for channame in channel_list: if channame in chan.name: chan.Gbar = 0.0
def setup_vclamp(compartment, name, delay1, width1, level1, gain=0.5e-5): """ Sets up a voltage clamp with 'name' on MOOSE 'compartment' object: adapted from squid.g in DEMOS (moose/genesis) Specify the 'delay1', 'width1' and 'level1' of the voltage to be applied to the compartment. Typically you need to adjust the PID 'gain' For perhaps the Davison 4-compartment mitral or the Davison granule: 0.5e-5 optimal gain - too high 0.5e-4 drives it to oscillate at high frequency, too low 0.5e-6 makes it have an initial overshoot (due to Na channels?) Returns a MOOSE table with the PID output. """ ## If /elec doesn't exists it creates /elec and returns a reference to it. ## If it does, it just returns its reference. _moose.Neutral('/elec') pulsegen = _moose.PulseGen('/elec/pulsegen' + name) vclamp = _moose.DiffAmp('/elec/vclamp' + name) vclamp.saturation = 999.0 vclamp.gain = 1.0 lowpass = _moose.RC('/elec/lowpass' + name) lowpass.R = 1.0 lowpass.C = 50e-6 # 50 microseconds tau PID = _moose.PIDController('/elec/PID' + name) PID.gain = gain PID.tau_i = 20e-6 PID.tau_d = 5e-6 PID.saturation = 999.0 # All connections should be written as source.connect('',destination,'') pulsegen.connect('outputSrc', lowpass, 'injectMsg') lowpass.connect('outputSrc', vclamp, 'plusDest') vclamp.connect('outputSrc', PID, 'commandDest') PID.connect('outputSrc', compartment, 'injectMsg') compartment.connect('VmSrc', PID, 'sensedDest') pulsegen.trigMode = 0 # free run pulsegen.baseLevel = -70e-3 pulsegen.firstDelay = delay1 pulsegen.firstWidth = width1 pulsegen.firstLevel = level1 pulsegen.secondDelay = 1e6 pulsegen.secondLevel = -70e-3 pulsegen.secondWidth = 0.0 vclamp_I = _moose.Table("/elec/vClampITable" + name) vclamp_I.stepMode = TAB_BUF #TAB_BUF: table acts as a buffer. vclamp_I.connect("inputRequest", PID, "output") vclamp_I.useClock(PLOTCLOCK) return vclamp_I
def tweak_field(moose_wildcard, field, assignment_string): """Tweak a specified field of all objects that match the moose_wildcard using assignment string. All identifiers in assignment string must be fields of the target object. Example: tweak_field('/mycell/##[Class=Compartment]', 'Rm', '1.5 / (3.1416 * diameter * length') will assign Rm to every compartment in mycell such that the specific membrane resistance is 1.5 Ohm-m2. """ if not isinstance(moose_wildcard, str): raise TypeError('moose_wildcard must be a string.') id_list = _moose.getWildcardList(moose_wildcard, True) expression = parser.expr(assignment_string) expr_list = expression.tolist() # This is a hack: I just tried out some possible syntax trees and # hand coded the replacement such that any identifier is replaced # by moose_obj.identifier def replace_fields_with_value(x): if len(x) > 1: if x[0] == symbol.power and x[1][0] == symbol.atom and x[1][1][ 0] == token.NAME: field = x[1][1][1] x[1] = [symbol.atom, [token.NAME, 'moose_obj']] x.append( [symbol.trailer, [token.DOT, '.'], [token.NAME, field]]) for item in x: if isinstance(item, list): replace_fields_with_value(item) return x tmp = replace_fields_with_value(expr_list) new_expr = parser.sequence2st(tmp) code = new_expr.compile() for moose_id in id_list: moose_obj = eval('_moose.%s(moose_id)' % (_moose.Neutral(moose_id).className)) value = eval(code) _moose.setField(moose_id, field, str(value))
def test_autoposition(self): """Simple check for automatic generation of positions. A spherical soma is created with 20 um diameter. A 100 compartment cable is created attached to it with each compartment of length 100 um. """ testid = 'test%s' % (uuid.uuid4()) container = _moose.Neutral('/test') model = _moose.Neuron('/test/%s' % (testid)) soma = _moose.Compartment('%s/soma' % (model.path)) soma.diameter = 20e-6 soma.length = 0.0 parent = soma comps = [] for ii in range(100): comp = _moose.Compartment('%s/comp_%d' % (model.path, ii)) comp.diameter = 10e-6 comp.length = 100e-6 _moose.connect(parent, 'raxial', comp, 'axial') comps.append(comp) parent = comp soma = autoposition(model) sigfig = 8 self.assertAlmostEqual(soma.x0, 0.0, sigfig) self.assertAlmostEqual(soma.y0, 0.0, sigfig) self.assertAlmostEqual(soma.z0, 0.0, sigfig) self.assertAlmostEqual(soma.x, 0.0, sigfig) self.assertAlmostEqual(soma.y, 0.0, sigfig) self.assertAlmostEqual(soma.z, soma.diameter / 2.0, sigfig) for ii, comp in enumerate(comps): print comp.path, ii self.assertAlmostEqual(comp.x0, 0, sigfig) self.assertAlmostEqual(comp.y0, 0.0, sigfig) self.assertAlmostEqual(comp.z0, soma.diameter / 2.0 + ii * 100e-6, sigfig) self.assertAlmostEqual(comp.x, 0.0, sigfig) self.assertAlmostEqual(comp.y, 0.0, sigfig) self.assertAlmostEqual(comp.z, soma.diameter / 2.0 + (ii + 1) * 100e-6, sigfig)
def setup_iclamp(compartment, name, delay1, width1, level1): """ Sets up a current clamp with 'name' on MOOSE 'compartment' object: Specify the 'delay1', 'width1' and 'level1' of the current pulse to be applied to the compartment. Returns the MOOSE pulsegen that sends the current pulse. """ ## If /elec doesn't exists it creates /elec and returns a reference to it. ## If it does, it just returns its reference. _moose.Neutral('/elec') pulsegen = _moose.PulseGen('/elec/pulsegen' + name) iclamp = _moose.DiffAmp('/elec/iclamp' + name) iclamp.saturation = 1e6 iclamp.gain = 1.0 pulsegen.trigMode = 0 # free run pulsegen.baseLevel = 0.0 pulsegen.firstDelay = delay1 pulsegen.firstWidth = width1 pulsegen.firstLevel = level1 pulsegen.secondDelay = 1e6 # to avoid repeat pulsegen.secondLevel = 0.0 pulsegen.secondWidth = 0.0 pulsegen.connect('output', iclamp, 'plusIn') iclamp.connect('output', compartment, 'injectMsg') return pulsegen
def resetSim(simpaths, simdt, plotdt, simmethod='hsolve'): """ For each of the MOOSE paths in simpaths, this sets the clocks and finally resets MOOSE. If simmethod=='hsolve', it sets up hsolve-s for each Neuron under simpaths, and clocks for hsolve-s too. """ print 'Solver:', simmethod _moose.setClock(INITCLOCK, simdt) _moose.setClock(ELECCLOCK, simdt) # The hsolve and ee methods use clock 1 _moose.setClock( CHANCLOCK, simdt) # hsolve uses clock 2 for mg_block, nmdachan and others. _moose.setClock(POOLCLOCK, simdt) # Ca/ion pools & funcs use clock 3 _moose.setClock(STIMCLOCK, simdt) # Ca/ion pools & funcs use clock 3 _moose.setClock(PLOTCLOCK, plotdt) # for tables for simpath in simpaths: ## User can connect [qty]Out of an element to input of Table or ## requestOut of Table to get[qty] of the element. ## Scheduling the Table to a clock tick, will call process() of the Table ## which will send a requestOut and overwrite any value set by input(), ## thus adding garbage value to the vector. Hence schedule only if ## input message is not connected to the Table. for table in _moose.wildcardFind(simpath + '/##[TYPE=Table]'): if len(table.neighbors['input']) == 0: _moose.useClock(PLOTCLOCK, table.path, 'process') _moose.useClock(ELECCLOCK, simpath + '/##[TYPE=PulseGen]', 'process') _moose.useClock(STIMCLOCK, simpath + '/##[TYPE=DiffAmp]', 'process') _moose.useClock(STIMCLOCK, simpath + '/##[TYPE=VClamp]', 'process') _moose.useClock(STIMCLOCK, simpath + '/##[TYPE=PIDController]', 'process') _moose.useClock(STIMCLOCK, simpath + '/##[TYPE=RC]', 'process') _moose.useClock(STIMCLOCK, simpath + '/##[TYPE=TimeTable]', 'process') _moose.useClock(ELECCLOCK, simpath + '/##[TYPE=LeakyIaF]', 'process') _moose.useClock(ELECCLOCK, simpath + '/##[TYPE=IntFire]', 'process') _moose.useClock(ELECCLOCK, simpath + '/##[TYPE=IzhikevichNrn]', 'process') _moose.useClock(ELECCLOCK, simpath + '/##[TYPE=SpikeGen]', 'process') _moose.useClock(ELECCLOCK, simpath + '/##[TYPE=Interpol]', 'process') _moose.useClock(ELECCLOCK, simpath + '/##[TYPE=Interpol2D]', 'process') _moose.useClock(CHANCLOCK, simpath + '/##[TYPE=HHChannel2D]', 'process') _moose.useClock(CHANCLOCK, simpath + '/##[TYPE=SynChan]', 'process') ## If simmethod is not hsolve, set clocks for the biophysics, ## else just put a clock on the hsolve: ## hsolve takes care of the clocks for the biophysics if 'hsolve' not in simmethod.lower(): print 'Using exp euler' _moose.useClock(INITCLOCK, simpath + '/##[TYPE=Compartment]', 'init') _moose.useClock(ELECCLOCK, simpath + '/##[TYPE=Compartment]', 'process') _moose.useClock(CHANCLOCK, simpath + '/##[TYPE=HHChannel]', 'process') _moose.useClock(POOLCLOCK, simpath + '/##[TYPE=CaConc]', 'process') _moose.useClock(POOLCLOCK, simpath + '/##[TYPE=Func]', 'process') else: # use hsolve, one hsolve for each Neuron print 'Using hsolve' element = _moose.Neutral(simpath) for childid in element.children: childobj = _moose.Neutral(childid) classname = childobj.className if classname in ['Neuron']: neuronpath = childobj.path h = _moose.HSolve(neuronpath + '/solve') h.dt = simdt h.target = neuronpath _moose.useClock(INITCLOCK, h.path, 'process') _moose.reinit()
def apply_to_tree(moose_wildcard, python_filter=None, value=None): """ Select objects by a moose/genesis wildcard, apply a python filter on them and apply a value on them. moose_wildcard - this follows GENESIS convention. {path}/#[{condition}] returns all elements directly under {path} that satisfy condition. For example: '/mynetwork/mycell_0/#[TYPE=Compartment]' will return all Compartment objects directly under mycell_0 in mynetwork. '{path}/##[{condition}]' will recursively go through all the objects that are under {path} (i.e. children, grandchildren, great-grandchildren and so on up to the leaf level) and a list of the ones meet {condition} will be obtained. Thus, '/mynetwork/##[TYPE=Compartment]' will return all compartments under mynetwork or its children, or children thereof and so on. python_filter - if a single string, it will be taken as a fieldname, and value will be assigned to this field. It can also be a lambda function returning True or False which will be applied to each id in the id list returned by moose wildcard search. Remember, the argument to the lambda will be an Id, so it is up to you to wrap it into a moose object of appropriate type. An example is: lambda moose_id: Compartment(moose_id).diameter < 2e-6 If your moose_wildcard selected objects of Compartment class, then this lambda function will select only those with diameter less than 2 um. value - can be a lambda function to apply arbitrary operations on the selected objects. If python_filter is a string it, the return value of applying the lambda for value() will assigned to the field specified by python_filter. But if it is value is a data object and {python_filter} is a string, then {value} will be assigned to the field named {python_filter}. If you want to assign Rm = 1e6 for each compartment in mycell whose name match 'axon_*': apply_to_tree('/mycell/##[Class=Compartment]', lambda x: 'axon_' in Neutral(x).name, lambda x: setattr(Compartment(x), 'Rm', 1e6)) [you must use setattr to assign value to a field because lambda functions don't allow assignments]. """ if not isinstance(moose_wildcard, str): raise TypeError('moose_wildcard must be a string.') id_list = _moose.getWildcardList(moose_wildcard, True) if isinstance(python_filter, types.LambdaType): id_list = [moose_id for moose_id in id_list if python_filter(moose_id)] elif isinstance(python_filter, str): id_list = [ moose_id for moose_id in id_list if hasattr( eval('_moose.%s(moose_id)' % (_moose.Neutral(moose_id).className)), python_filter) ] else: pass if isinstance(value, types.LambdaType): if isinstance(python_filter, str): for moose_id in id_list: moose_obj = eval('_moose.%s(moose_id)' % (_moose.Neutral(moose_id).className)) setattr(moose_obj, python_filter, value(moose_id)) else: for moose_id in id_list: value(moose_id) else: if isinstance(python_filter, str): for moose_id in id_list: moose_obj = eval('_moose.%s(moose_id)' % (_moose.Neutral(moose_id).className)) setattr(moose_obj, python_filter, value) else: raise TypeError( 'Second argument must be a string specifying a field to assign to when third argument is a value' )
def test_printtree(self): s = _moose.Neutral('/cell') soma = _moose.Neutral('%s/soma' % (s.path)) d1 = _moose.Neutral('%s/d1' % (soma.path)) d2 = _moose.Neutral('%s/d2' % (soma.path)) d3 = _moose.Neutral('%s/d3' % (d1.path)) d4 = _moose.Neutral('%s/d4' % (d1.path)) d5 = _moose.Neutral('%s/d5' % (s.path)) orig_stdout = sys.stdout sys.stdout = _sio() printtree(s) expected = """ cell | |__ soma | | | |__ d1 | | | | | |__ d3 | | | | | |__ d4 | | | |__ d2 | |__ d5 """ self.assertEqual(sys.stdout.getvalue(), expected) sys.stdout = _sio() s1 = _moose.Neutral('cell1') c1 = _moose.Neutral('%s/c1' % (s1.path)) c2 = _moose.Neutral('%s/c2' % (c1.path)) c3 = _moose.Neutral('%s/c3' % (c1.path)) c4 = _moose.Neutral('%s/c4' % (c2.path)) c5 = _moose.Neutral('%s/c5' % (c3.path)) c6 = _moose.Neutral('%s/c6' % (c3.path)) c7 = _moose.Neutral('%s/c7' % (c4.path)) c8 = _moose.Neutral('%s/c8' % (c5.path)) printtree(s1) expected1 = """ cell1 | |__ c1 | |__ c2 | | | |__ c4 | | | |__ c7 | |__ c3 | |__ c5 | | | |__ c8 | |__ c6 """ self.assertEqual(sys.stdout.getvalue(), expected1)
def connect_CaConc(compartment_list, temperature=None): """ Connect the Ca pools and channels within each of the compartments in compartment_list Ca channels should have a child Mstring named 'ion' with value set in MOOSE. Ca dependent channels like KCa should have a child Mstring called 'ionDependency' with value set in MOOSE. Call this only after instantiating cell so that all channels and pools have been created. """ for compartment in compartment_list: caconc = None for child in compartment.children: neutralwrap = _moose.Neutral(child) if neutralwrap.className == 'CaConc': caconc = _moose.CaConc(child) break if caconc is not None: child = get_child_Mstring(caconc, 'phi') if child is not None: caconc.B = float( child.value ) # B = phi by definition -- see neuroml 1.8.1 defn else: ## B has to be set for caconc based on thickness of Ca shell and compartment l and dia, ## OR based on the Mstring phi under CaConc path. ## I am using a translation from Neuron for mitral cell, hence this method. ## In Genesis, gmax / (surfacearea*thick) is set as value of B! caconc.B = 1 / (2*FARADAY) / \ (math.pi*compartment.diameter*compartment.length * caconc.thick) for child in compartment.children: neutralwrap = _moose.Neutral(child) if neutralwrap.className == 'HHChannel': channel = _moose.HHChannel(child) ## If child Mstring 'ion' is present and is Ca, connect channel current to caconc for childid in channel.children: # in async13, gates which have not been created still 'exist' # i.e. show up as a child, but cannot be wrapped. try: child = _moose.element(childid) if child.className == 'Mstring': child = _moose.Mstring(child) if child.name == 'ion': if child.value in ['Ca', 'ca']: _moose.connect(channel, 'IkOut', caconc, 'current') #print 'Connected IkOut of',channel.path,'to current of',caconc.path ## temperature is used only by Nernst part here... if child.name == 'nernst_str': nernst = _moose.Nernst(channel.path + '/nernst') nernst_params = string.split( child.value, ',') nernst.Cout = float(nernst_params[0]) nernst.valence = float(nernst_params[1]) nernst.Temperature = temperature _moose.connect(nernst, 'Eout', channel, 'setEk') _moose.connect(caconc, 'concOut', nernst, 'ci') #print 'Connected Nernst',nernst.path except TypeError: pass if neutralwrap.className == 'HHChannel2D': channel = _moose.HHChannel2D(child) ## If child Mstring 'ionDependency' is present, connect caconc Ca conc to channel for childid in channel.children: # in async13, gates which have not been created still 'exist' # i.e. show up as a child, but cannot be wrapped. try: child = _moose.element(childid) if child.className == 'Mstring' and child.name == 'ionDependency': child = _moose.Mstring(child) if child.value in ['Ca', 'ca']: _moose.connect(caconc, 'concOut', channel, 'concen') #print 'Connected concOut of',caconc.path,'to concen of',channel.path except TypeError: pass