def writeGraphviz(pat='/##', filename=None, filterList=[]): '''This is a generic function. It takes the the pattern, search for paths and write a graphviz file. ''' def ignore(line): for f in filterList: if f in line: return True return False pathList = getMoosePaths(pat) dot = [] dot.append("digraph G {") dot.append("\tconcentrate=true") for p in pathList: if ignore(p): continue else: p = re.sub('[]()]', '', p) dot.append('\t'+' -> '.join(filter(None, p.split('/')))) dot.append('}') dot = '\n'.join(dot) if not filename: print(dot) else: with open(filename, 'w') as graphviz: debug.printDebug("INFO" , "Writing topology to file {}".format(filename) ) graphviz.write(dot) return
def writeGraphviz(pat='/##', filename=None, filterList=[]): '''This is a generic function. It takes the the pattern, search for paths and write a graphviz file. ''' def ignore(line): for f in filterList: if f in line: return True return False pathList = getMoosePaths(pat) dot = [] dot.append("digraph G {") dot.append("\tconcentrate=true") for p in pathList: if ignore(p): continue else: p = p.translate(None, '[]()') dot.append('\t'+' -> '.join(filter(None, p.split('/')))) dot.append('}') dot = '\n'.join(dot) if not filename: print(dot) else: with open(filename, 'w') as graphviz: debug.printDebug("INFO" , "Writing topology to file {}".format(filename) ) graphviz.write(dot) return
def testBench(self, entity, newFileDict): """Generate the test-bench """ # if this entity is already a testbench then remove it from the list and # add a new one. eXml = self.vhdlXml.find(".//entity[@name='{0}']".format(entity)) debug.printDebug("STEP" , "Generating testbench for entity {0}".format(entity) ) if eXml.attrib['noPort'] == "true": # It's a testbench. fileName = eXml.attrib['file'] debug.printDebug("WARN" , "Entity {} in {} is a testbench. Ignoring it..".format( entity , fileName ) ) # add a new testbench. Need to find an entity which is its children. fileSet = self.fileDict[entity] self.fileDict[entity].remove(fileName) newFileDict[entity] = fileSet else : # no testbench fileSet = set(self.fileDict[entity]) tbName = self.prefix + entity + ".vhd" tbEntity = "tb_"+entity fileSet.add( self.generateTestBench(entity, tbName, self.testVectorFile) ) newFileDict[tbEntity] = fileSet
def setupTable(name, obj, qtyname, tablePath=None, threshold=None): '''This is replacement function for moose.utils.setupTable It stores qtyname from obj. ''' assert qtyname[0].isupper(), "First character must be uppercase character" debug.printDebug("DEBUG" , "Setting up table for: {} -> get{}".format(obj.path, qtyname) ) if tablePath is None: tablePath = '{}/{}'.format(obj.path, 'data') debug.printDebug("WARN" , "Using default table path: {}".format(tablePath) , frame = inspect.currentframe() ) if not moose.exists(obj.path): raise RuntimeError("Unknown path {}".format(obj.path)) moose.Neutral(tablePath) table = moose.Table('{}/{}'.format(tablePath, name)) if threshold is None: moose.connect(table, "requestOut", obj, "get{}".format(qtyname)) else: raise UserWarning("TODO: Table with threshold is not implemented yet") return table
def writeGraphviz(pat="/##", filename=None, filterList=[]): """This is a generic function. It takes the the pattern, search for paths and write a graphviz file. """ def ignore(line): for f in filterList: if f in line: return True return False pathList = getMoosePaths(pat) dot = [] dot.append("digraph G {") dot.append("\tconcentrate=true") for p in pathList: if ignore(p): continue else: p = re.sub("[]()]", "", p) dot.append("\t" + " -> ".join(filter(None, p.split("/")))) dot.append("}") dot = "\n".join(dot) if not filename: print(dot) else: with open(filename, "w") as graphviz: debug.printDebug("INFO", "Writing topology to file {}".format(filename)) graphviz.write(dot) return
def integateAndFireMechanism(self, mechanism): """ Integrate and fire mechanism """ mech_params = mechanism.findall(".//{"+self.bio+"}parameter") for parameter in mech_params: paramName = parameter.attrib['name'] if paramName == 'inject': self.mooseCell.inject = float(parameter.attrib["value"])*self.Ifactor elif paramName == 'Rm': self.mooseCell.Rm = float(parameter.attrib["value"])*self.Rfactor elif paramName == 'Cm': self.mooseCell.Cm = float(parameter.attrib["value"])*self.Cfactor elif paramName == 'Em': self.mooseCell.Em = float(parameter.attrib["value"])*self.Efactor elif paramName == 'v_reset': # voltage after spike, typicaly below resting self.mooseCell.Vreset = float(parameter.attrib["value"])*self.Efactor self.mooseCell.initVm = self.mooseCell.Vreset elif paramName == 'threshold': # firing threshold potential self.mooseCell.Vthreshold = \ float(parameter.attrib["value"])*self.Efactor elif paramName == 't_refrac': # min refractory time before next spike msg = "Use this refractory period in simulation" debug.printDebug("TODO" , msg, frame=inspect.currentframe()) self.mooseCell.refractoryPeriod = \ float(parameter.attrib["value"])*self.Tfactor elif paramName == 'inject': # inject into soma self.mooseCell.refractoryPeriod = \ float(parameter.attrib["value"])*self.Ifactor
def make_cml_function(self, element, fn_name, concdep=None): fn_type = element.attrib['expr_form'] if fn_type in ['exponential', 'sigmoid', 'exp_linear']: fn = self.make_function(fn_name, fn_type, rate=float(element.attrib['rate']), midpoint=float(element.attrib['midpoint']), scale=float(element.attrib['scale'])) elif fn_type == 'generic': # OOPS! These expressions should be in SI units, since I converted # to SI Ideally I should not convert to SI and have the user # consistently use one or the other Or convert constants in these # expressions to SI, only voltage and ca_conc appear! NO! SEE # ABOVE, for calculating values for tables, I use units specified in # xml file, then I convert to SI while writing to MOOSE internal # tables. expr_string = element.attrib['expr'] if concdep is None: ca_name = '' # no Ca dependence else: ca_name = ',' + concdep.attrib['variable_name'] # Ca dependence expr_string = self.replace(expr_string, 'alpha', 'self.alpha(v' + ca_name + ')') expr_string = self.replace(expr_string, 'beta', 'self.beta(v' + ca_name + ')') fn = self.make_function(fn_name, fn_type, expr_string=expr_string, concdep=concdep) else: debug.printDebug("ERR", "Unsupported function type %s " % fn_type, frame=inspect.currentframe()) sys.exit()
def main(self, files, args) : ''' Top most function in this folder.''' self.generateTB = args.generate_tb self.testVectorFile = args.test_vector_file self.topModule = args.top_module # We must delete all files automatically generated before (if any). All # such files have auto_generated_ prefix. newFiles = set() for file in files : if re.search(self.prefix, file) : pass else : newFiles.add(file) files = newFiles debug.printDebug("STEP", "Building design out of files.") parseVhdl = vhdl_parser.VHDLParser(topdir=self.topdir) self.vhdlXml = parseVhdl.parseFiles(files) debug.printDebug("STEP", "Processing design and building hierarchy") self.getHierarchy() # dump the xml for debugging purpose. with open("vhdl.xml", "w") as f: f.write(ET.tostring(self.vhdlXml)) with open("hier.xml", "w") as f: f.write(ET.tostring(self.hierXml)) # Run each top-entity self.runDesign(self.generateTB)
def parseWithoutValidation(modelName, modelPath): xmlParser = etree.XMLParser(remove_comments=True) try: xmlRootElem = etree.parse(modelPath, xmlParser) except Exception as e: debug.printDebug("ERROR", "Parsing of {0} failed.".format(modelPath)) debug.printDebug("DEBUG", "Error: {0}".format(e)) raise RuntimeError, "Failed to parse XML" return xmlRootElem
def parseWithoutValidation(modelName, modelPath) : xmlParser = etree.XMLParser(remove_comments=True) try : xmlRootElem = etree.parse(modelPath, xmlParser) except Exception as e : debug.printDebug("ERROR", "Parsing of {0} failed.".format(modelPath)) debug.printDebug("DEBUG", "Error: {0}".format(e)) raise RuntimeError, "Failed to parse XML" return xmlRootElem
def readIonConcML(self, ionConcElement, units="SI units"): if units == 'Physiological Units': # see pg 219 (sec 13.2) of Book of Genesis Vfactor = 1e-3 # V from mV Tfactor = 1e-3 # s from ms Gfactor = 1e1 # S/m^2 from mS/cm^2 concfactor = 1e6 # mol/m^3 from mol/cm^3 Lfactor = 1e-2 # m from cm Ifactor = 1e-6 # A from microA else: Vfactor = 1.0 Tfactor = 1.0 Gfactor = 1.0 concfactor = 1.0 Lfactor = 1.0 Ifactor = 1.0 # creates /library in MOOSE tree; elif present, wraps moose.Neutral(self.libraryPath + '') ionSpecies = ionConcElement.find('./{' + self.cml + '}ion_species') if ionSpecies is not None: if not 'ca' in ionSpecies.attrib['name']: msg = "Sorry, I cannot handle non-Ca-ion pools. Exiting..." debug.printDebug("ERR", msg, frame=inspect.currentframe()) sys.exit(1) capoolName = ionConcElement.attrib['name'] debug.printDebug( "INFO", "Loading Ca pool {} into {}".format(capoolName, self.libraryPath)) caPool = moose.CaConc(self.libraryPath + '/' + capoolName) poolModel = ionConcElement.find('./{' + self.cml + '}decaying_pool_model') caPool.CaBasal = float(poolModel.attrib['resting_conc']) * concfactor caPool.Ca_base = float(poolModel.attrib['resting_conc']) * concfactor if 'decay_constant' in poolModel.attrib: caPool.tau = float(poolModel.attrib['decay_constant']) * Tfactor elif 'inv_decay_constant' in poolModel.attrib: caPool.tau = 1.0 / float(poolModel.attrib['inv_decay_constant']) \ * Tfactor # Only one of pool_volume_info or fixed_pool_info should be present, but # not checking volInfo = poolModel.find('./{' + self.cml + '}pool_volume_info') if volInfo is not None: caPool.thick = float(volInfo.attrib['shell_thickness']) * Lfactor fixedPoolInfo = poolModel.find('./{' + self.cml + '}fixed_pool_info') if fixedPoolInfo is not None: # Put in phi under the caPool, so that it can be used instead of # thickness to set B (see section 19.2 in Book of Genesis) caPool_phi = moose.Mstring(caPool.path + '/phi') caPool_phi.value = str( float(fixedPoolInfo.attrib['phi']) \ * concfactor/Ifactor/Tfactor )
def readIonConcML(self, ionConcElement, units="SI units"): if units == 'Physiological Units': # see pg 219 (sec 13.2) of Book of Genesis Vfactor = 1e-3 # V from mV Tfactor = 1e-3 # s from ms Gfactor = 1e1 # S/m^2 from mS/cm^2 concfactor = 1e6 # mol/m^3 from mol/cm^3 Lfactor = 1e-2 # m from cm Ifactor = 1e-6 # A from microA else: Vfactor = 1.0 Tfactor = 1.0 Gfactor = 1.0 concfactor = 1.0 Lfactor = 1.0 Ifactor = 1.0 # creates /library in MOOSE tree; elif present, wraps moose.Neutral(self.libraryPath+'') ionSpecies = ionConcElement.find('./{'+self.cml+'}ion_species') if ionSpecies is not None: if not 'ca' in ionSpecies.attrib['name']: msg = "Sorry, I cannot handle non-Ca-ion pools. Exiting..." debug.printDebug("ERR", msg, frame=inspect.currentframe()) sys.exit(1) capoolName = ionConcElement.attrib['name'] debug.printDebug("INFO" , "Loading Ca pool {} into {}".format(capoolName , self.libraryPath) ) caPool = moose.CaConc(self.libraryPath+'/'+capoolName) poolModel = ionConcElement.find('./{'+self.cml+'}decaying_pool_model') caPool.CaBasal = float(poolModel.attrib['resting_conc']) * concfactor caPool.Ca_base = float(poolModel.attrib['resting_conc']) * concfactor if 'decay_constant' in poolModel.attrib: caPool.tau = float(poolModel.attrib['decay_constant']) * Tfactor elif 'inv_decay_constant' in poolModel.attrib: caPool.tau = 1.0 / float(poolModel.attrib['inv_decay_constant']) \ * Tfactor # Only one of pool_volume_info or fixed_pool_info should be present, but # not checking volInfo = poolModel.find('./{'+self.cml+'}pool_volume_info') if volInfo is not None: caPool.thick = float(volInfo.attrib['shell_thickness']) * Lfactor fixedPoolInfo = poolModel.find('./{'+self.cml+'}fixed_pool_info') if fixedPoolInfo is not None: # Put in phi under the caPool, so that it can be used instead of # thickness to set B (see section 19.2 in Book of Genesis) caPool_phi = moose.Mstring(caPool.path+'/phi') caPool_phi.value = str( float(fixedPoolInfo.attrib['phi']) \ * concfactor/Ifactor/Tfactor )
def simulateUsingVsim(self, entityName, fileSet): cmd.runCommand(["vlib", self.workdir]) for file in fileSet: file = os.path.join(self.topdir, file) debug.printDebug("STEP" , "Compiling {0} using modelsim".format(file) ) cmd.runCommand(["vcom", file]) if None: cmd.runCommand(["vsim", "-c", "-do", "run {}; quit".format(self.runtime) , entityName] , stdout=None, stderr=None )
def __init__(self, nml_params): self.cml = 'http://morphml.org/channelml/schema' self.libraryPath = config.libraryPath self.nml_params = nml_params temp = '{0}'.format(nml_params['temperature']) if temp is None or len(temp) == 0: self.temperature = 32.0 debug.printDebug( "INFO", "Using default temp of {0} C".format(self.temperature)) else: self.temperature = float(temp) debug.printDebug("INFO", "Using temperature {0}".format(self.temperature))
def addParameterToCompartment(self, parameter, cell, options): """ Add parameter to compartment """ cellName = options['cellName'] mechName = options['mechName'] passive = options['passive'] paramName = parameter.attrib['name'] if passive: if paramName in ['gmax']: self.set_group_compartment_param( cell, cellName, parameter, 'RM', self.RMfactor * 1.0 / float(parameter.attrib["value"]), self.bio) elif paramName in ['e', 'erev']: self.set_group_compartment_param( cell, cellName, parameter, 'Em', self.Efactor * float(parameter.attrib["value"]), self.bio) elif paramName in ['inject']: self.set_group_compartment_param( cell, cellName, parameter, 'inject', self.Ifactor * float(parameter.attrib["value"]), self.bio) else: msg = "Yo programmar of MorphML! You did not implemented" msg += " parameter {0} in mechanism {1} ".format( paramName, mechName) debug.printDebug("WARN", msg, frame=inspect.currentframe()) else: if paramName in ['gmax']: gmaxval = float( eval(parameter.attrib["value"], {"__builtins__": None}, {})) self.set_group_compartment_param(cell, cellName, parameter, 'Gbar', self.Gfactor * gmaxval, self.bio, mechName) elif paramName in ['e', 'erev']: self.set_group_compartment_param( cell, cellName, parameter, 'Ek', self.Efactor * float(parameter.attrib["value"]), self.bio, mechName) elif paramName in ['depth']: # has to be type Ion Concentration! self.set_group_compartment_param( cell, cellName, parameter, 'thick', self.length_factor * float(parameter.attrib["value"]), self.bio, mechName) else: msg = "Yo programmar of MorphML! You did not implemented" msg += " parameter {0} in mechanism {1} ".format( paramName, mechName) debug.printDebug("WARN", msg, frame=inspect.currentframe())
def analyze(self, filepath) : ''' Analyze a file. ''' workdir = self.workdir if "ghdl" in self.compiler: command = "ghdl -a --workdir={0} --work=work \ --ieee=synopsys {1}".format(workdir, filepath) cmd.runCommand(shlex.split(command)) elif "vsim" in self.compiler: cmd.runCommand(["vlib", self.workdir]) cmd.runCommand(["vcom", filepath]) else: debug.printDebug("WARN" , "Unknown compiler %s " % self.compiler ) return None
def readMorphMLFromFile(self, filename, params={}): """ specify global params as a dict (presently none implemented) returns { cellName1 : segDict, ... } see readMorphML(...) for segDict """ debug.printDebug("INFO", "{}".format(filename)) tree = ET.parse(filename) neuroml_element = tree.getroot() cellsDict = {} for cell in neuroml_element.findall('.//{' + self.neuroml + '}cell'): cellDict = self.readMorphML(cell, params, neuroml_element.attrib['lengthUnits']) cellsDict.update(cellDict) return cellsDict
def __init__(self, nml_params): self.cml='http://morphml.org/channelml/schema' self.libraryPath = config.libraryPath self.nml_params = nml_params temp = '{0}'.format(nml_params['temperature']) if temp is None or len(temp) == 0: self.temperature = 32.0 debug.printDebug("INFO" , "Using default temp of {0} C".format(self.temperature) ) else: self.temperature = float(temp) debug.printDebug("INFO" , "Using temperature {0}".format(self.temperature) )
def elaborate(self, entityname) : ''' Elaborate the file ''' if "ghdl" in self.compiler: workdir = self.workdir debug.printDebug("STEP", "Elaborating entity {0}".format(entityname)) bin = os.path.join(self.workdir, entityname) # Before elaboration, check if binary already exists. If yes then remove # it. if os.path.exists(bin): os.remove(bin) command = "ghdl -e --workdir={0} --work=work -o {1} {2}".format(workdir , bin, entityname) cmd.runCommand(shlex.split(command)) else: pass
def readSynapseML(self, synapseElement, units="SI units"): # see pg 219 (sec 13.2) of Book of Genesis if 'Physiological Units' in units: Vfactor = 1e-3 # V from mV Tfactor = 1e-3 # s from ms Gfactor = 1e-3 # S from mS elif 'SI Units' in units: Vfactor = 1.0 Tfactor = 1.0 Gfactor = 1.0 else: debug.printDebug("ERROR", "Wrong units {0}".format(units)) raise UserWarning, "Wrong value or parameter {0}".format(units) # creates /library in MOOSE tree; elif present, wraps # NOTE: This path is created by NeuroML now in __init__. Disabling, # Dilawar Singh #moose.Neutral(self.libraryPath+'') if utils.neuroml_debug: synName = synapseElement.attrib['name'] msg = "Loading synapse : %s into library ." % synName debug.printDebug("INFO", msg) self.mooseSynp = moose.SynChan( os.path.join(self.libraryPath, synapseElement.attrib['name'])) doub_exp_syn = synapseElement.find('./{' + self.cml + '}doub_exp_syn') self.mooseSynp.Ek = float(doub_exp_syn.attrib['reversal_potential']) \ * Vfactor self.mooseSynp.Gbar = float(doub_exp_syn.attrib['max_conductance'])\ * Gfactor # seconds self.mooseSynp.tau1 = float(doub_exp_syn.attrib['rise_time']) * Tfactor # second\s self.mooseSynp.tau2 = float( doub_exp_syn.attrib['decay_time']) * Tfactor # The delay and weight can be set only after connecting a spike event # generator. delay and weight are arrays: multiple event messages can # be connected to a single synapse self.mooseSynp_graded = moose.Mstring(self.mooseSynp.path + '/graded') self.mooseSynp_graded.value = 'False' self.mooseSynp_mgblock = moose.Mstring(self.mooseSynp.path + '/mgblock') self.mooseSynp_mgblock.value = 'False'
def make_cml_function(self, element, fn_name, concdep=None): fn_type = element.attrib['expr_form'] if fn_type in ['exponential','sigmoid','exp_linear']: fn = self.make_function( fn_name , fn_type , rate=float(element.attrib['rate']) , midpoint=float(element.attrib['midpoint']) , scale=float(element.attrib['scale'] ) ) elif fn_type == 'generic': # OOPS! These expressions should be in SI units, since I converted # to SI Ideally I should not convert to SI and have the user # consistently use one or the other Or convert constants in these # expressions to SI, only voltage and ca_conc appear! NO! SEE # ABOVE, for calculating values for tables, I use units specified in # xml file, then I convert to SI while writing to MOOSE internal # tables. expr_string = element.attrib['expr'] if concdep is None: ca_name = '' # no Ca dependence else: ca_name = ','+concdep.attrib['variable_name'] # Ca dependence expr_string = self.replace( expr_string , 'alpha' , 'self.alpha(v'+ca_name+')' ) expr_string = self.replace( expr_string , 'beta' , 'self.beta(v'+ca_name+')' ) fn = self.make_function( fn_name , fn_type , expr_string=expr_string , concdep=concdep ) else: debug.printDebug("ERR" , "Unsupported function type %s " % fn_type , frame=inspect.currentframe() ) sys.exit()
def parseXMLs(commandLineArgs, validate=False) : xmlRootElemDict = collections.defaultdict(list) models = vars(commandLineArgs) for model in models : if models[model] : for modelPath in models[model] : debug.printDebug("INFO", "Parsing {0}".format(models[model])) if validate : # parse model and valid it with schama modelXMLRootElem = parseAndValidateWithSchema(model, modelPath) else : # Simple parse the model without validating it with schema. modelXMLRootElem = parseWithoutValidation(model, modelPath) if modelXMLRootElem : xmlRootElemDict[model].append((modelXMLRootElem, modelPath)) assert len(xmlRootElemDict) > 0 return xmlRootElemDict
def readMorphMLFromFile(self, filename, params={}): """ specify global params as a dict (presently none implemented) returns { cellName1 : segDict, ... } see readMorphML(...) for segDict """ debug.printDebug("INFO", "{}".format(filename)) tree = ET.parse(filename) neuroml_element = tree.getroot() cellsDict = {} for cell in neuroml_element.findall('.//{'+self.neuroml+'}cell'): cellDict = self.readMorphML( cell , params , neuroml_element.attrib['lengthUnits'] ) cellsDict.update(cellDict) return cellsDict
def run(self, entityName, time=1000) : ''' Running the binary ''' if "ghdl" in self.compiler: self.simulator = self.compiler workdir = self.workdir bin = workdir+"/"+entityName debug.printDebug("STEP", "Simulating design") if not os.path.isfile(bin) : msg = "Error : Binary not found. Existing." debug.printDebug("WARN", msg) return # Else run the command. command = "{0} --vcd={1}.vcd --stop-time={2}ns \n".format( bin, workdir+"/"+entityName, time) cmd.runCommand(shlex.split(command)) if "vsim" in self.compiler: print("using vsim")
def readSynapseML(self, synapseElement, units="SI units"): # see pg 219 (sec 13.2) of Book of Genesis if 'Physiological Units' in units: Vfactor = 1e-3 # V from mV Tfactor = 1e-3 # s from ms Gfactor = 1e-3 # S from mS elif 'SI Units' in units: Vfactor = 1.0 Tfactor = 1.0 Gfactor = 1.0 else: debug.printDebug("ERROR", "Wrong units {0}".format(units)) raise UserWarning, "Wrong value or parameter {0}".format(units) # creates /library in MOOSE tree; elif present, wraps # NOTE: This path is created by NeuroML now in __init__. Disabling, # Dilawar Singh #moose.Neutral(self.libraryPath+'') if utils.neuroml_debug: synName = synapseElement.attrib['name'] msg = "Loading synapse : %s into library ." % synName debug.printDebug("INFO", msg) self.mooseSynp = moose.SynChan(os.path.join(self.libraryPath , synapseElement.attrib['name'])) doub_exp_syn = synapseElement.find('./{' + self.cml + '}doub_exp_syn') self.mooseSynp.Ek = float(doub_exp_syn.attrib['reversal_potential']) \ * Vfactor self.mooseSynp.Gbar = float(doub_exp_syn.attrib['max_conductance'])\ * Gfactor # seconds self.mooseSynp.tau1 = float(doub_exp_syn.attrib['rise_time']) * Tfactor # second\s self.mooseSynp.tau2 = float(doub_exp_syn.attrib['decay_time'])*Tfactor # The delay and weight can be set only after connecting a spike event # generator. delay and weight are arrays: multiple event messages can # be connected to a single synapse self.mooseSynp_graded = moose.Mstring(self.mooseSynp.path+'/graded') self.mooseSynp_graded.value = 'False' self.mooseSynp_mgblock = moose.Mstring(self.mooseSynp.path+'/mgblock') self.mooseSynp_mgblock.value = 'False'
def addMechanism(self, mechanism, cell, cellName): """ Add mechanism to cell. """ mechName = mechanism.attrib["name"] debug.printDebug("STEP", "Loading mechanism {0}".format(mechName)) passive = False if "passive_conductance" in mechanism.attrib: if mechanism.attrib['passive_conductance'].lower() == "true": passive = True # ONLY creates channel if at least one parameter (like gmax) is # specified in the xml Neuroml does not allow you to specify all # default values. However, granule cell example in neuroconstruct has # Ca ion pool without a parameter, applying default values to all # compartments! mech_params = mechanism.findall(".//{" + self.bio + "}parameter") ## if no params, apply all default values to all compartments if len(mech_params) == 0: compartments = self.cellDictByCableId[cellName][1].values() for c in compartments: self.set_compartment_param(c, None, 'default', mechName) # if params are present, apply params to specified cable/compartment # groups. for parameter in mech_params: options = { 'cellName': cellName, 'mechName': mechName, 'passive': passive } self.addParameterToCompartment(parameter, cell, options) # Connect the Ca pools and channels Am connecting these at the very end # so that all channels and pools have been created Note: this function # is in moose.utils not moose.neuroml.utils ! # temperature should be in Kelvin for Nernst temperature = self.stringToFloat(self.temperature) moose_utils.connect_CaConc( list(self.cellDictByCableId[cellName][1].values()), temperature + neuroml_utils.ZeroCKelvin)
def addMechanism(self, mechanism, cell, cellName): """ Add mechanism to cell. """ mechName = mechanism.attrib["name"] debug.printDebug("STEP", "Loading mechanism {0}".format(mechName)) passive = False if "passive_conductance" in mechanism.attrib: if mechanism.attrib['passive_conductance'].lower() == "true": passive = True # ONLY creates channel if at least one parameter (like gmax) is # specified in the xml Neuroml does not allow you to specify all # default values. However, granule cell example in neuroconstruct has # Ca ion pool without a parameter, applying default values to all # compartments! mech_params = mechanism.findall(".//{"+self.bio+"}parameter") ## if no params, apply all default values to all compartments if len(mech_params) == 0: compartments = self.cellDictByCableId[cellName][1].values() for c in compartments: self.set_compartment_param(c, None, 'default', mechName) # if params are present, apply params to specified cable/compartment # groups. for parameter in mech_params: options = { 'cellName' : cellName , 'mechName' : mechName , 'passive' : passive } self.addParameterToCompartment(parameter, cell, options) # Connect the Ca pools and channels Am connecting these at the very end # so that all channels and pools have been created Note: this function # is in moose.utils not moose.neuroml.utils ! # temperature should be in Kelvin for Nernst temperature = self.stringToFloat(self.temperature) moose_utils.connect_CaConc( list(self.cellDictByCableId[cellName][1].values()) , temperature + neuroml_utils.ZeroCKelvin )
def parseXMLs(commandLineArgs, validate=False): xmlRootElemDict = collections.defaultdict(list) models = vars(commandLineArgs) for model in models: if models[model]: for modelPath in models[model]: debug.printDebug("INFO", "Parsing {0}".format(models[model])) if validate: # parse model and valid it with schama modelXMLRootElem = parseAndValidateWithSchema( model, modelPath) else: # Simple parse the model without validating it with schema. modelXMLRootElem = parseWithoutValidation(model, modelPath) if modelXMLRootElem: xmlRootElemDict[model].append( (modelXMLRootElem, modelPath)) assert len(xmlRootElemDict) > 0 return xmlRootElemDict
def findCompiler(language): if language == 'vhdl': # Try for ghdl if not findExecutable("ghdl"): if not findExecutable("vsim"): debug.printDebug("ERROR" , "Can't find a suitable compiler on your system" + " Use -c switch from command line" ) sys.exit(0) else: return findExecutable("vsim") else: return findExecutable("ghdl") else: debug.printDebug("ERROR" , "Unknown language {}".format(language) ) sys.exit(0)
def parseAndValidateWithSchema(modelName, modelPath) : prefixPath = '' if modelName == 'xml' : schemaPath = os.path.join(prefixPath, 'schema/moose/moose.xsd') if not os.path.isfile(schemaPath) : debug.printDebug("WARN", "Schema {0} does not exists..".format(schemaPath)) try : schemaH = open(schemaPath, "r") schemaText = schemaH.read() schemaH.close() except Exception as e : debug.printDebug("WARN", "Error reading schema for validation."+ " Falling back to validation-disabled parser." + " Failed with error {0}".format(e)) return parseWithoutValidation(modelName, modelPath) # Now we have the schema text schema = etree.XMLSchema(etree.XML(schemaText)) xmlParser = etree.XMLParser(schema=schema, remove_comments=True) with open(modelPath, "r") as xmlTextFile : return etree.parse(xmlTextFile, xmlParser)
def integateAndFireMechanism(self, mechanism): """ Integrate and fire mechanism """ mech_params = mechanism.findall(".//{" + self.bio + "}parameter") for parameter in mech_params: paramName = parameter.attrib['name'] if paramName == 'inject': self.mooseCell.inject = float( parameter.attrib["value"]) * self.Ifactor elif paramName == 'Rm': self.mooseCell.Rm = float( parameter.attrib["value"]) * self.Rfactor elif paramName == 'Cm': self.mooseCell.Cm = float( parameter.attrib["value"]) * self.Cfactor elif paramName == 'Em': self.mooseCell.Em = float( parameter.attrib["value"]) * self.Efactor elif paramName == 'v_reset': # voltage after spike, typicaly below resting self.mooseCell.Vreset = float( parameter.attrib["value"]) * self.Efactor self.mooseCell.initVm = self.mooseCell.Vreset elif paramName == 'threshold': # firing threshold potential self.mooseCell.Vthreshold = \ float(parameter.attrib["value"])*self.Efactor elif paramName == 't_refrac': # min refractory time before next spike msg = "Use this refractory period in simulation" debug.printDebug("TODO", msg, frame=inspect.currentframe()) self.mooseCell.refractoryPeriod = \ float(parameter.attrib["value"])*self.Tfactor elif paramName == 'inject': # inject into soma self.mooseCell.refractoryPeriod = \ float(parameter.attrib["value"])*self.Ifactor
def parseAndValidateWithSchema(modelName, modelPath): prefixPath = '' if modelName == 'xml': schemaPath = os.path.join(prefixPath, 'schema/moose/moose.xsd') if not os.path.isfile(schemaPath): debug.printDebug("WARN", "Schema {0} does not exists..".format(schemaPath)) try: schemaH = open(schemaPath, "r") schemaText = schemaH.read() schemaH.close() except Exception as e: debug.printDebug( "WARN", "Error reading schema for validation." + " Falling back to validation-disabled parser." + " Failed with error {0}".format(e)) return parseWithoutValidation(modelName, modelPath) # Now we have the schema text schema = etree.XMLSchema(etree.XML(schemaText)) xmlParser = etree.XMLParser(schema=schema, remove_comments=True) with open(modelPath, "r") as xmlTextFile: return etree.parse(xmlTextFile, xmlParser)
def getNextLevelsOfHier(self, archName, hasParents, childLess , alreadyAddedArcs): ''' Get the components of a xmlElem. @param elemXml : Xml element of archName @param archName : name of the entity of this architecture ''' if archName not in alreadyAddedArcs.keys(): debug.printDebug("WARN", "Funtion validations error"\ +": {0} should have been added to args 2".format(archName)) return None comps = self.vhdlXml.findall(".//architecture[@of='{0}']/*".format(archName)) archXml = alreadyAddedArcs[archName] if len(comps) < 1 : debug.printDebug("DEBUG" , "No component found for {0}".format(archName) ) childLess.add(archName) return for comp in comps : compName = comp.attrib['name'] instanceOf = comp.attrib['instance_of'] debug.printDebug("DEBUG" , "Component {0} found for entity {1}".format( compName , archName ) ) if comp.attrib['isInstantiated'] == "true": hasParents.add(compName) # Now check if architecture of this component was already added. if compName in alreadyAddedArcs.keys() : compXml = alreadyAddedArcs[compName] archXml.append(compXml) else : compXml = ET.Element("component") compXml.attrib['name'] = compName compXml.attrib['instance_of'] = instanceOf alreadyAddedArcs[compName] = compXml archXml.append(compXml) else : debug.printDebug("WARN" , "Component {0} is not instantited.".format(compName) )
def runCommand(command, shell=False, **kwargs): if type(command) is list: pass else: command = shlex.split(command) try: p = subprocess.Popen(command , stdin = kwargs.get('stdin', subprocess.PIPE) , stdout = kwargs.get('stdout', subprocess.PIPE) , stderr = kwargs.get('stderr', subprocess.PIPE) ) p.wait() except Exception as e: debug.printDebug("ERROR", "Failed with exception %s " % e) debug.printDebug("DEBUG", "Command was: {}".format(command)) sys.exit(0) else: debug.printDebug("INFO" , "Success : {}".format(" ".join(command)) ) return
def set_compartment_param(self, compartment, name, value, mechName): """ Set the param for the compartment depending on name and mechName. """ if name == 'CM': compartment.Cm = value * math.pi * compartment.diameter * compartment.length elif name == 'RM': compartment.Rm = value / (math.pi * compartment.diameter * compartment.length) elif name == 'RA': compartment.Ra = value * compartment.length / \ (math.pi*(compartment.diameter/2.0)**2) elif name == 'Em': compartment.Em = value elif name == 'initVm': compartment.initVm = value elif name == 'inject': msg = " {0} inject {1} A.".format(compartment.name, value) debug.printDebug("INFO", msg) compartment.inject = value elif mechName is 'synapse': # synapse being added to the compartment # these are potential locations, we do not actually make synapses. # I assume below that compartment name has _segid at its end # get segment id from compartment name segid = moose_methods.getCompartmentId(compartment.name) self.segDict[segid][5].append(value) # spikegen being added to the compartment elif mechName is 'spikegen': # these are potential locations, we do not actually make the # spikegens. spikegens for different synapses can have different # thresholds, hence include synapse_type in its name value contains # name of synapse i.e. synapse_type #spikegen = moose.SpikeGen(compartment.path+'/'+value+'_spikegen') #moose.connect(compartment,"VmSrc",spikegen,"Vm") pass elif mechName is not None: # if mechanism is not present in compartment, deep copy from library if not moose.exists(compartment.path + '/' + mechName): # if channel does not exist in library load it from xml file if not moose.exists(self.libraryPath + "/" + mechName): cmlR = ChannelML(self.nml_params) model_filename = mechName + '.xml' model_path = neuroml_utils.find_first_file( model_filename, self.model_dir) if model_path is not None: cmlR.readChannelMLFromFile(model_path) else: msg = 'Mechanism {0}: files {1} not found under {2}'\ .format( mechName , model_filename , self.model_dir ) debug.printDebug("ERROR", msg, frame=inspect.currentframe()) sys.exit(0) neutralObj = moose.Neutral(self.libraryPath + "/" + mechName) # Ion concentration pool if 'CaConc' == neutralObj.className: libcaconc = moose.CaConc(self.libraryPath + "/" + mechName) # deep copies the library caconc under the compartment caconc = moose.copy(libcaconc, compartment, mechName) caconc = moose.CaConc(caconc) # CaConc connections are made later using connect_CaConc() # Later, when calling connect_CaConc, B is set for caconc # based on thickness of Ca shell and compartment l and dia # OR based on the Mstring phi under CaConc path. channel = None elif 'HHChannel2D' == neutralObj.className: ## HHChannel2D libchannel = moose.HHChannel2D(self.libraryPath + "/" + mechName) ## deep copies the library channel under the compartment channel = moose.copy(libchannel, compartment, mechName) channel = moose.HHChannel2D(channel) moose.connect(channel, 'channel', compartment, 'channel') elif 'HHChannel' == neutralObj.className: ## HHChannel libchannel = moose.HHChannel(self.libraryPath + "/" + mechName) # deep copies the library channel under the compartment channel = moose.copy(libchannel, compartment, mechName) channel = moose.HHChannel(channel) moose.connect(channel, 'channel', compartment, 'channel') # if mechanism is present in compartment, just wrap it else: neutralObj = moose.Neutral(compartment.path + '/' + mechName) # Ion concentration pool if 'CaConc' == neutralObj.className: # wraps existing channel caconc = moose.CaConc(compartment.path + '/' + mechName) channel = None elif 'HHChannel2D' == neutralObj.className: ## HHChannel2D # wraps existing channel channel = moose.HHChannel2D(compartment.path + '/' + mechName) elif 'HHChannel' == neutralObj.className: ## HHChannel # wraps existing channel channel = moose.HHChannel(compartment.path + '/' + mechName) if name == 'Gbar': # if CaConc, neuroConstruct uses gbar for thickness or phi if channel is None: # If child Mstring 'phi' is present, set gbar as phi BUT, # value has been multiplied by Gfactor as a Gbar, SI or # physiological not known here, ignoring Gbar for CaConc, # instead of passing units here child = moose_utils.get_child_Mstring(caconc, 'phi') if child is not None: #child.value = value pass else: #caconc.thick = value pass else: # if ion channel, usual Gbar channel.Gbar = value * math.pi * compartment.diameter \ * compartment.length elif name == 'Ek': channel.Ek = value # thick seems to be NEURON's extension to NeuroML level 2. elif name == 'thick': # JUST THIS WILL NOT DO - HAVE TO SET B based on this thick! caconc.thick = value # Later, when calling connect_CaConc, B is set for caconc based # on thickness of Ca shell and compartment l and dia. OR based # on the Mstring phi under CaConc path. if neuroml_utils.neuroml_debug: msg = "Setting {0} for {1} value {2}".format( name, compartment.path, value) debug.printDebug("DEBUG", msg, frame=inspect.currentframe())
def readChannelML(self, channelElement, params={}, units="SI units"): """Loads a single channel """ # I first calculate all functions assuming a consistent system of units. # While filling in the A and B tables, I just convert to SI. Also # convert gmax and Erev. if 'Physiological Units' in units: # see pg 219 (sec 13.2) of Book of Genesis Vfactor = 1e-3 # V from mV Tfactor = 1e-3 # s from ms Gfactor = 1e1 # S/m^2 from mS/cm^2 concfactor = 1e6 # Mol = mol/m^-3 from mol/cm^-3 elif 'SI Units' in units: Vfactor = 1.0 Tfactor = 1.0 Gfactor = 1.0 concfactor = 1.0 else: debug.printDebug("ERR", "wrong units %s. Existing... " % units, frame=inspect.currentframe()) raise UserWarning, "Unknown units" # creates /library in MOOSE tree; elif present, wraps channel_name = channelElement.attrib['name'] if utils.neuroml_debug: msg = "Loading channel {} into {} ".format(channel_name, self.libraryPath) debug.printDebug("INFO", msg) IVrelation = channelElement.find('./{' + self.cml + '}current_voltage_relation') concdep = IVrelation.find('./{' + self.cml + '}conc_dependence') cPath = os.path.join(self.libraryPath, channel_name) if concdep is None: channel = moose.HHChannel(cPath) else: channel = moose.HHChannel2D(cPath) if IVrelation.attrib['cond_law'] == "ohmic": channel.Gbar = float(IVrelation.attrib['default_gmax']) * Gfactor channel.Ek = float(IVrelation.attrib['default_erev']) * Vfactor channelIon = moose.Mstring(channel.path + '/ion') channelIon.value = IVrelation.attrib['ion'] if concdep is not None: channelIonDependency = moose.Mstring(channel.path + '/ionDependency') channelIonDependency.value = concdep.attrib['ion'] nernstnote = IVrelation.find('./{' + utils.meta_ns + '}notes') if nernstnote is not None: # the text in nernstnote is "Nernst,Cout=<float>,z=<int>" nernst_params = string.split(nernstnote.text, ',') if nernst_params[0] == 'Nernst': nernstMstring = moose.Mstring(channel.path + '/nernst_str') nernstMstring.value = str( float(string.split(nernst_params[1], '=')[1]) * concfactor) + ',' + str( int(string.split(nernst_params[2], '=')[1])) gates = IVrelation.findall('./{' + self.cml + '}gate') if len(gates) > 3: msg = "Sorry! Maximum x, y, and z (three) gates are possible in\ MOOSE/Genesis" debug.printDebug("ERR", msg, frame=inspect.currentframe()) raise UserWarning, "Bad value or parameter" # These are the names that MOOSE uses to create gates. gate_full_name = ['gateX', 'gateY', 'gateZ'] # if impl_prefs tag is present change VMIN, VMAX and NDIVS impl_prefs = channelElement.find('./{' + self.cml + '}impl_prefs') if impl_prefs is not None: table_settings = impl_prefs.find('./{' + self.cml + '}table_settings') # some problem here... disable VMIN_here = float(table_settings.attrib['min_v']) VMAX_here = float(table_settings.attrib['max_v']) NDIVS_here = int(table_settings.attrib['table_divisions']) dv_here = (VMAX_here - VMIN_here) / NDIVS_here else: # default VMIN, VMAX and dv are in SI convert them to current # calculation units used by channel definition while loading into # tables, convert them back to SI VMIN_here = utils.VMIN / Vfactor VMAX_here = utils.VMAX / Vfactor NDIVS_here = utils.NDIVS dv_here = utils.dv / Vfactor offset = IVrelation.find('./{' + self.cml + '}offset') if offset is None: vNegOffset = 0.0 else: vNegOffset = float(offset.attrib['value']) self.parameters = [] for parameter in channelElement.findall('.//{' + self.cml + '}parameter'): self.parameters.append( (parameter.attrib['name'], float(parameter.attrib['value']))) for num, gate in enumerate(gates): # if no q10settings tag, the q10factor remains 1.0 if present but no # gate attribute, then set q10factor if there is a gate attribute, # then set it only if gate attrib matches gate name self.q10factor = 1.0 self.gate_name = gate.attrib['name'] q10sets = IVrelation.findall('./{' + self.cml + '}q10_settings') for q10settings in q10sets: # self.temperature from neuro.utils if 'gate' in list(q10settings.attrib.keys()): if q10settings.attrib['gate'] == self.gate_name: self.setQ10(q10settings) break else: self.setQ10(q10settings) # HHChannel2D crashing on setting Xpower! temperamental! If you # print something before, it gives cannot creategate from copied # channel, else crashes Setting power first. This is necessary # because it also initializes the gate's internal data structures as # a side effect. Alternatively, gates can be initialized explicitly # by calling HHChannel.createGate(). gate_power = float(gate.get('instances')) if num == 0: channel.Xpower = gate_power if concdep is not None: channel.Xindex = "VOLT_C1_INDEX" elif num == 1: channel.Ypower = gate_power if concdep is not None: channel.Yindex = "VOLT_C1_INDEX" elif num == 2: channel.Zpower = gate_power if concdep is not None: channel.Zindex = "VOLT_C1_INDEX" ## Getting handle to gate using the gate's path. gate_path = os.path.join(channel.path, gate_full_name[num]) if concdep is None: moosegate = moose.HHGate(gate_path) # set SI values inside MOOSE moosegate.min = VMIN_here * Vfactor moosegate.max = VMAX_here * Vfactor moosegate.divs = NDIVS_here ## V.IMP to get smooth curves, else even with 3000 divisions ## there are sudden transitions. moosegate.useInterpolation = True else: moosegate = moose.HHGate2D(gate_path) # If alpha and beta functions exist, make them here for transition in gate.findall('./{' + self.cml + '}transition'): # make python functions with names of transitions... fn_name = transition.attrib['name'] # I assume that transitions if present are called alpha and beta # for forwand backward transitions... if fn_name in ['alpha', 'beta']: self.make_cml_function(transition, fn_name, concdep) else: debug.printDebug( "ERROR", "Unsupported transition {0}".format(fn_name)) sys.exit() time_course = gate.find('./{' + self.cml + '}time_course') # tau is divided by self.q10factor in make_function() thus, it gets # divided irrespective of <time_course> tag present or not. if time_course is not None: self.make_cml_function(time_course, 'tau', concdep) steady_state = gate.find('./{' + self.cml + '}steady_state') if steady_state is not None: self.make_cml_function(steady_state, 'inf', concdep) if concdep is None: ca_name = '' # no Ca dependence else: # Ca dependence ca_name = ',' + concdep.attrib['variable_name'] # Create tau() and inf() if not present, from alpha() and beta() for fn_element, fn_name, fn_expr in [ (time_course, 'tau', "1/(alpha+beta)"), (steady_state, 'inf', "alpha/(alpha+beta)") ]: # put in args for alpha and beta, could be v and Ca dep. expr_string = self.replace(fn_expr, 'alpha', 'self.alpha(v' + ca_name + ')') expr_string = self.replace(expr_string, 'beta', 'self.beta(v' + ca_name + ')') # if time_course/steady_state are not present, then alpha annd # beta transition elements should be present, and fns created. if fn_element is None: self.make_function(fn_name, 'generic', expr_string=expr_string, concdep=concdep) # non Ca dependent channel if concdep is None: # while calculating, use the units used in xml defn, while # filling in table, I convert to SI units. v0 = VMIN_here - vNegOffset n_entries = NDIVS_here + 1 tableA = [0.0] * n_entries tableB = [0.0] * n_entries for i in range(n_entries): v = v0 + (i * dv_here) inf = self.inf(v) tau = self.tau(v) # convert to SI before writing to table # qfactor is already in inf and tau tableA[i] = (inf / tau) / Tfactor tableB[i] = (1.0 / tau) / Tfactor moosegate.tableA = tableA moosegate.tableB = tableB ## Ca dependent channel else: # UNITS: while calculating, use the units used in xml defn, # while filling in table, I convert to SI units. Note here Ca # units do not enter, but units of CaMIN, CaMAX and ca_conc in # fn expr should match. v = VMIN_here - vNegOffset CaMIN = float(concdep.attrib['min_conc']) CaMAX = float(concdep.attrib['max_conc']) CaNDIVS = 100 dCa = (CaMAX - CaMIN) / CaNDIVS # CAREFUL!: tableA = [[0.0]*(CaNDIVS+1)]*(NDIVS_here+1) will not # work! * does a shallow copy, same list will get repeated 200 # times! Thus setting tableA[35][1] = 5.0 will set all rows, # 1st col to 5.0!!!! tableA = [[0.0] * (CaNDIVS + 1) for i in range(NDIVS_here + 1)] tableB = [[0.0] * (CaNDIVS + 1) for i in range(NDIVS_here + 1)] for i in range(NDIVS_here + 1): Ca = CaMIN for j in range(CaNDIVS + 1): inf = self.inf(v, Ca) tau = self.tau(v, Ca) # convert to SI (Tfactor) before writing to table # qfactor is already in inf and tau tableA[i][j] = (inf / tau) / Tfactor tableB[i][j] = (1.0 / tau) / Tfactor Ca += dCa v += dv_here # Presently HHGate2D doesn't allow the setting of tables as 2D # vectors directly #moosegate.tableA = tableA #moosegate.tableB = tableB # Instead, I wrap the interpol2D objects inside HHGate2D and set # the tables moosegate_tableA = moose.Interpol2D(moosegate.path + '/tableA') # set SI values inside MOOSE moosegate_tableA.xmin = VMIN_here * Vfactor moosegate_tableA.xmax = VMAX_here * Vfactor moosegate_tableA.xdivs = NDIVS_here #moosegate_tableA.dx = dv_here*Vfactor moosegate_tableA.ymin = CaMIN * concfactor moosegate_tableA.ymax = CaMAX * concfactor moosegate_tableA.ydivs = CaNDIVS #moosegate_tableA.dy = dCa*concfactor moosegate_tableA.tableVector2D = tableA moosegate_tableB = moose.Interpol2D(moosegate.path + '/tableB') ## set SI values inside MOOSE moosegate_tableB.xmin = VMIN_here * Vfactor moosegate_tableB.xmax = VMAX_here * Vfactor moosegate_tableB.xdivs = NDIVS_here #moosegate_tableB.dx = dv_here*Vfactor moosegate_tableB.ymin = CaMIN * concfactor moosegate_tableB.ymax = CaMAX * concfactor moosegate_tableB.ydivs = CaNDIVS #moosegate_tableB.dy = dCa*concfactor moosegate_tableB.tableVector2D = tableB
def addSegment(self, cellName, segnum, segment): """ Adding segment to cell. """ run_dia = 0.0 running_comp = None running_dia_nums = 0 segmentname = segment.attrib['name'] debug.printDebug( "DEBUG", "Adding segment {} in cell {}".format(segmentname, cellName)) # cable is an optional attribute. WARNING: Here I assume it is always # present. cableid = segment.attrib['cable'] segmentid = segment.attrib['id'] # Old cableid still running, hence don't start a new compartment, skip # to next segment. if cableid == self.running_cableid: self.cellDictBySegmentId[cellName][1][segmentid] = running_comp proximal = segment.find('./{' + self.mml + '}proximal') if proximal is not None: run_dia += float( proximal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 distal = segment.find('./{' + self.mml + '}distal') if distal is not None: run_dia += float( distal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 # new cableid starts, hence start a new compartment; also finish # previous / last compartment. else: # Create a new compartment, the moose "hsolve" method assumes # compartments to be asymmetric compartments and symmetrizes them # but that is not what we want when translating from Neuron # which has only symcompartments -- so be careful! # just segmentname is NOT unique - eg: mitral bbmit exported from # NEURON. mooseCompname = moose_methods.moosePath(segmentname, segmentid) mooseComppath = self.mooseCell.path + '/' + mooseCompname mooseComp = moose.Compartment(mooseComppath) self.cellDictBySegmentId[cellName][1][segmentid] = mooseComp # Cables are grouped and densities set for cablegroups. Hence I # need to refer to segment according to which cable they belong # to.. self.cellDictByCableId[cellName][1][cableid] = mooseComp self.running_cableid = cableid running_segid = segmentid running_comp = mooseComp run_dia = 0.0 running_dia_nums = 0 if 'parent' in segment.attrib: # I assume the parent is created before the child so that I can # immediately # connect the child. parentid = segment.attrib['parent'] parent = self.cellDictBySegmentId[cellName][1][parentid] # It is always assumed that axial of parent is connected to # raxial of moosesegment THIS IS WHAT GENESIS readcell() # DOES!!! UNLIKE NEURON! THIS IS IRRESPECTIVE OF WHETHER # PROXIMAL x,y,z OF PARENT = PROXIMAL x,y,z OF CHILD. THIS IS # ALSO IRRESPECTIVE OF fraction_along_parent SPECIFIED IN # CABLE! THUS THERE WILL BE NUMERICAL DIFFERENCES BETWEEN # MOOSE/GENESIS and NEURON. moosesegment sends Ra and Vm to # parent, parent sends only Vm actually for symmetric # compartment, both parent and moosesegment require each # other's Ra/2, but axial and raxial just serve to distinguish # ends. moose.connect(parent, 'axial', mooseComp, 'raxial') else: parent = None proximal = segment.find('./{' + self.mml + '}proximal') if proximal is None: # If proximal tag is not present, then parent attribute MUST be # present in the segment tag! if proximal is not present, then # by default the distal end of the parent is the proximal end # of the child mooseComp.x0 = parent.x mooseComp.y0 = parent.y mooseComp.z0 = parent.z else: mooseComp.x0 = float(proximal.attrib["x"]) * self.length_factor mooseComp.y0 = float(proximal.attrib["y"]) * self.length_factor mooseComp.z0 = float(proximal.attrib["z"]) * self.length_factor run_dia += float( proximal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 distal = segment.find('./{' + self.mml + '}distal') if distal is not None: run_dia += float( distal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 # finished creating new compartment Update the end position, # diameter and length, and segDict of this comp/cable/section with # each segment that is part of this cable (assumes contiguous # segments in xml). This ensures that we don't have to do any # 'closing ceremonies', if a new cable is encoutered in next # iteration. if distal is not None: running_comp.x = float(distal.attrib["x"]) * self.length_factor running_comp.y = float(distal.attrib["y"]) * self.length_factor running_comp.z = float(distal.attrib["z"]) * self.length_factor # Set the compartment diameter as the average diameter of all the # segments in this section running_comp.diameter = run_dia / float(running_dia_nums) # Set the compartment length running_comp.length = math.sqrt( (running_comp.x-running_comp.x0)**2+\ (running_comp.y-running_comp.y0)**2+\ (running_comp.z-running_comp.z0)**2 ) # NeuroML specs say that if (x0,y0,z0)=(x,y,z), then round # compartment e.g. soma. In Moose set length = dia to give same # surface area as sphere of dia. if running_comp.length == 0.0: running_comp.length = running_comp.diameter # Set the segDict the empty list at the end below will get # populated with the potential synapses on this segment, in # function set_compartment_param(..) self.segDict[running_segid] = [ running_comp.name, (running_comp.x0, running_comp.y0, running_comp.z0), (running_comp.x, running_comp.y, running_comp.z), running_comp.diameter, running_comp.length, [] ] if neuroml_utils.neuroml_debug: debug.printDebug( "STEP", "Set up compartment/section %s" % running_comp.name)
def addSegment(self, cellName, segnum, segment): """ Adding segment to cell. """ run_dia = 0.0 running_comp = None running_dia_nums = 0 segmentname = segment.attrib['name'] debug.printDebug("DEBUG" , "Adding segment {} in cell {}".format(segmentname, cellName) ) # cable is an optional attribute. WARNING: Here I assume it is always # present. cableid = segment.attrib['cable'] segmentid = segment.attrib['id'] # Old cableid still running, hence don't start a new compartment, skip # to next segment. if cableid == self.running_cableid: self.cellDictBySegmentId[cellName][1][segmentid] = running_comp proximal = segment.find('./{'+self.mml+'}proximal') if proximal is not None: run_dia += float(proximal.attrib["diameter"])*self.length_factor running_dia_nums += 1 distal = segment.find('./{'+self.mml+'}distal') if distal is not None: run_dia += float(distal.attrib["diameter"])*self.length_factor running_dia_nums += 1 # new cableid starts, hence start a new compartment; also finish # previous / last compartment. else: # Create a new compartment, the moose "hsolve" method assumes # compartments to be asymmetric compartments and symmetrizes them # but that is not what we want when translating from Neuron # which has only symcompartments -- so be careful! # just segmentname is NOT unique - eg: mitral bbmit exported from # NEURON. mooseCompname = moose_methods.moosePath(segmentname, segmentid) mooseComppath = self.mooseCell.path + '/' + mooseCompname mooseComp = moose.Compartment(mooseComppath) self.cellDictBySegmentId[cellName][1][segmentid] = mooseComp # Cables are grouped and densities set for cablegroups. Hence I # need to refer to segment according to which cable they belong # to.. self.cellDictByCableId[cellName][1][cableid] = mooseComp self.running_cableid = cableid running_segid = segmentid running_comp = mooseComp run_dia = 0.0 running_dia_nums = 0 if 'parent' in segment.attrib: # I assume the parent is created before the child so that I can # immediately # connect the child. parentid = segment.attrib['parent'] parent = self.cellDictBySegmentId[cellName][1][parentid] # It is always assumed that axial of parent is connected to # raxial of moosesegment THIS IS WHAT GENESIS readcell() # DOES!!! UNLIKE NEURON! THIS IS IRRESPECTIVE OF WHETHER # PROXIMAL x,y,z OF PARENT = PROXIMAL x,y,z OF CHILD. THIS IS # ALSO IRRESPECTIVE OF fraction_along_parent SPECIFIED IN # CABLE! THUS THERE WILL BE NUMERICAL DIFFERENCES BETWEEN # MOOSE/GENESIS and NEURON. moosesegment sends Ra and Vm to # parent, parent sends only Vm actually for symmetric # compartment, both parent and moosesegment require each # other's Ra/2, but axial and raxial just serve to distinguish # ends. moose.connect(parent, 'axial', mooseComp, 'raxial') else: parent = None proximal = segment.find('./{'+self.mml+'}proximal') if proximal is None: # If proximal tag is not present, then parent attribute MUST be # present in the segment tag! if proximal is not present, then # by default the distal end of the parent is the proximal end # of the child mooseComp.x0 = parent.x mooseComp.y0 = parent.y mooseComp.z0 = parent.z else: mooseComp.x0 = float(proximal.attrib["x"])*self.length_factor mooseComp.y0 = float(proximal.attrib["y"])*self.length_factor mooseComp.z0 = float(proximal.attrib["z"])*self.length_factor run_dia += float(proximal.attrib["diameter"])*self.length_factor running_dia_nums += 1 distal = segment.find('./{'+self.mml+'}distal') if distal is not None: run_dia += float(distal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 # finished creating new compartment Update the end position, # diameter and length, and segDict of this comp/cable/section with # each segment that is part of this cable (assumes contiguous # segments in xml). This ensures that we don't have to do any # 'closing ceremonies', if a new cable is encoutered in next # iteration. if distal is not None: running_comp.x = float(distal.attrib["x"])*self.length_factor running_comp.y = float(distal.attrib["y"])*self.length_factor running_comp.z = float(distal.attrib["z"])*self.length_factor # Set the compartment diameter as the average diameter of all the # segments in this section running_comp.diameter = run_dia / float(running_dia_nums) # Set the compartment length running_comp.length = math.sqrt( (running_comp.x-running_comp.x0)**2+\ (running_comp.y-running_comp.y0)**2+\ (running_comp.z-running_comp.z0)**2 ) # NeuroML specs say that if (x0,y0,z0)=(x,y,z), then round # compartment e.g. soma. In Moose set length = dia to give same # surface area as sphere of dia. if running_comp.length == 0.0: running_comp.length = running_comp.diameter # Set the segDict the empty list at the end below will get # populated with the potential synapses on this segment, in # function set_compartment_param(..) self.segDict[running_segid] = [ running_comp.name , (running_comp.x0 , running_comp.y0 , running_comp.z0) , (running_comp.x,running_comp.y,running_comp.z) , running_comp.diameter , running_comp.length , [] ] if neuroml_utils.neuroml_debug: debug.printDebug( "STEP" , "Set up compartment/section %s" % running_comp.name )
def generateTestVector(self, entityName) : top = self.vhdlXml.attrib['dir'] debug.printDebug("TODO", "Generating vector.test file.") # call this function now. #test.testEntity(entityName, top) return
def runDesign(self, generateTB): """ Run the damn design """ # check for compiler. If it does not exists, quit. self.topdir = self.vhdlXml.attrib['dir'] compileXml = ET.SubElement(self.vhdlXml, "compiler") compileXml.attrib['name'] = self.compiler if self.topModule is None and len(self.moduleList) > 0: self.topModule = self.moduleList[0].strip() elif self.topModule: pass else: debug.printDebug("WARN" , "Could not find any top-module %s " % self.topModule , frame = inspect.currentframe() ) return 0 self.topEntities = list() for t in self.vhdlXml.findall('.//entity[@name]'): # topModule is a list of entities. if t.get('name') in self.topModule: self.topEntities.append(t) # Now work on all entities collected. self.fileDict = dict() for te in self.topEntities : # Files needed to elaborate the design. files = set() neededEntity = set() topEntityName = te.attrib['name'] neededEntity.add(topEntityName) children = te.findall("component") for child in children : neededEntity.add(child.attrib['instance_of']) # get files we need to compile to elaborate this entity. for entityName in neededEntity : entity = self.vhdlXml.find( "entity[@name='{0}']".format(entityName) ) if entity is not None : fileOfEntity = entity.attrib['file'] files.add(fileOfEntity) else : raise UserWarning, "Entity {0} not found".format(entity) self.fileDict[topEntityName] = files # If generateTB is set then ignore the previous TB and generate a new one. # Else execute the design as it is. if not generateTB: debug.printDebug("INFO" , "Not generating testbenches. In fact doing nothing more" ) return None else: newFileDict = dict() [self.testBench(file, newFileDict) for file in self.fileDict] # Copy the new file list to old one. self.fileDict = newFileDict # Great, now simulate. for entity in self.fileDict: self.runATopEntity(entity, self.fileDict[entity])
def readMorphML(self, cell, params={}, lengthUnits="micrometer"): """ returns {cellName:segDict} where segDict = { segid1 : [ segname , (proximalx,proximaly,proximalz) , (distalx,distaly,distalz),diameter,length,[potential_syn1, ... ] ] , ... } segname is "<name>_<segid>" because 1) guarantees uniqueness, 2) later scripts obtain segid from the compartment's name! """ debug.printDebug("DEBUG", "Entered function readMorphML") if lengthUnits in ['micrometer','micron']: self.length_factor = 1e-6 else: self.length_factor = 1.0 cellName = cell.attrib["name"] if cellName == 'LIF': self.mooseCell = moose.LeakyIaF(self.cellPath+'/'+cellName) self.segDict = {} else: # using moose Neuron class - in previous version 'Cell' class # Chaitanya. self.mooseCell = moose.Neuron(self.cellPath+'/'+cellName) self.cellDictBySegmentId[cellName] = [self.mooseCell,{}] self.cellDictByCableId[cellName] = [self.mooseCell,{}] self.segDict = {} # load morphology and connections between compartments Many neurons # exported from NEURON have multiple segments in a section Combine # those segments into one Compartment / section assume segments of # a compartment/section are in increasing order and assume all # segments of a compartment/section have the same cableid findall() # returns elements in document order: self.running_cableid = '' running_segid = '' segments = cell.findall(".//{"+self.mml+"}segment") segmentstotal = len(segments) for segnum, segment in enumerate(segments): self.addSegment(cellName, segnum, segment) # load cablegroups into a dictionary self.cablegroupsDict = {} # Two ways of specifying cablegroups in neuroml 1.x # <cablegroup>s with list of <cable>s cablegroups = cell.findall(".//{"+self.mml+"}cablegroup") for cablegroup in cablegroups: cablegroupname = cablegroup.attrib['name'] self.cablegroupsDict[cablegroupname] = [] for cable in cablegroup.findall(".//{"+self.mml+"}cable"): cableid = cable.attrib['id'] self.cablegroupsDict[cablegroupname].append(cableid) # <cable>s with list of <meta:group>s cables = cell.findall(".//{"+self.mml+"}cable") for cable in cables: cableid = cable.attrib['id'] cablegroups = cable.findall(".//{"+self.meta+"}group") for cablegroup in cablegroups: cablegroupname = cablegroup.text if cablegroupname in list(self.cablegroupsDict.keys()): self.cablegroupsDict[cablegroupname].append(cableid) else: self.cablegroupsDict[cablegroupname] = [cableid] # Add bioPhysics to the cell self.addBiophysics(cell, cellName) # load connectivity / synapses into the compartments connectivity = cell.find(".//{"+self.neuroml+"}connectivity") if connectivity is not None: self.addConnectivity(cell, cellName, connectivity) return {cellName:self.segDict}
def main(): # Argument parser. description = '''Write testbench for vhdl and run it using ghdl/vsim.''' parser = argparse.ArgumentParser(description=description) parser.add_argument('--design-directory', '-d', metavar='design_directory' , nargs=1 , action='append' , required = True , help = 'Top directory containing your VHDL design.' ) parser.add_argument('--language', '-l' , metavar = 'language' , nargs=1 , default = "vhdl" , help = 'Which language (supported : vhdl )' ) parser.add_argument('--compiler', '-c' , metavar='compiler' , required = False , help = "Optional: Specify a compiler or I'll try to guess on system" ) parser.add_argument('--top-module', '-t', metavar='top_module' , nargs = 1 , required = False , default = None , help = 'Optional : Top module in your design.' ) parser.add_argument('--test-vector-file', '-v', metavar='test_vector' , required = False , default = None , help = 'Test vector file which test-bench should use' ) parser.add_argument('--generate-tb', '-r', metavar='auto_test' , nargs = 1 , required = False , default = True , help = 'Testbench will be generated automatically.' ) class Args: pass args = Args() parser.parse_args(namespace=args) if args.test_vector_file: args.test_vector_file = os.path.join(os.getcwd(), args.test_vector_file) if not os.path.isfile(args.test_vector_file): debug.printDebug("ERROR" , "Test vector file %s not found " % args.test_vector_file ) sys.exit(-11) else: pass if args.language == "vhdl": file_regex = ".*\.vhdl?$" files = findListings(args.design_directory, regex=file_regex) if len(files) < 1 : debug.printDebug("WARN" , "No file is found with regex {0} in directories {1}".format( file_regex , args.d) ) sys.exit(-10); topDir = findTopDir(args.design_directory) compiler = args.compiler if not compiler: compiler = findCompiler("vhdl") vhdlObj = vhdl.VHDL(topDir, compiler) vhdlObj.main(files, args) else: debug.printDebug("INFO", "Unsupported language : {0}".format(args.l)) debug.printDebug("DEBUG", "Languge specified {0}".format(args.l)) raise UserWarning("Unsupported language. {0}".format(args.l))
def set_compartment_param(self, compartment, name, value, mechName): """ Set the param for the compartment depending on name and mechName. """ if name == 'CM': compartment.Cm = value *math.pi*compartment.diameter*compartment.length elif name == 'RM': compartment.Rm = value/(math.pi*compartment.diameter*compartment.length) elif name == 'RA': compartment.Ra = value * compartment.length / \ (math.pi*(compartment.diameter/2.0)**2) elif name == 'Em': compartment.Em = value elif name == 'initVm': compartment.initVm = value elif name == 'inject': msg = " {0} inject {1} A.".format(compartment.name, value) debug.printDebug("INFO", msg) compartment.inject = value elif mechName is 'synapse': # synapse being added to the compartment # these are potential locations, we do not actually make synapses. # I assume below that compartment name has _segid at its end # get segment id from compartment name segid = moose_methods.getCompartmentId(compartment.name) self.segDict[segid][5].append(value) # spikegen being added to the compartment elif mechName is 'spikegen': # these are potential locations, we do not actually make the # spikegens. spikegens for different synapses can have different # thresholds, hence include synapse_type in its name value contains # name of synapse i.e. synapse_type #spikegen = moose.SpikeGen(compartment.path+'/'+value+'_spikegen') #moose.connect(compartment,"VmSrc",spikegen,"Vm") pass elif mechName is not None: # if mechanism is not present in compartment, deep copy from library if not moose.exists(compartment.path+'/'+mechName): # if channel does not exist in library load it from xml file if not moose.exists(self.libraryPath+"/"+mechName): cmlR = ChannelML(self.nml_params) model_filename = mechName+'.xml' model_path = neuroml_utils.find_first_file( model_filename , self.model_dir ) if model_path is not None: cmlR.readChannelMLFromFile(model_path) else: msg = 'Mechanism {0}: files {1} not found under {2}'\ .format( mechName , model_filename , self.model_dir ) debug.printDebug("ERROR" , msg , frame = inspect.currentframe() ) sys.exit(0) neutralObj = moose.Neutral(self.libraryPath+"/"+mechName) # Ion concentration pool if 'CaConc' == neutralObj.className: libcaconc = moose.CaConc(self.libraryPath+"/"+mechName) # deep copies the library caconc under the compartment caconc = moose.copy(libcaconc,compartment,mechName) caconc = moose.CaConc(caconc) # CaConc connections are made later using connect_CaConc() # Later, when calling connect_CaConc, B is set for caconc # based on thickness of Ca shell and compartment l and dia # OR based on the Mstring phi under CaConc path. channel = None elif 'HHChannel2D' == neutralObj.className : ## HHChannel2D libchannel = moose.HHChannel2D(self.libraryPath+"/"+mechName) ## deep copies the library channel under the compartment channel = moose.copy(libchannel,compartment,mechName) channel = moose.HHChannel2D(channel) moose.connect(channel,'channel',compartment,'channel') elif 'HHChannel' == neutralObj.className : ## HHChannel libchannel = moose.HHChannel(self.libraryPath+"/"+mechName) # deep copies the library channel under the compartment channel = moose.copy(libchannel,compartment,mechName) channel = moose.HHChannel(channel) moose.connect(channel,'channel',compartment,'channel') # if mechanism is present in compartment, just wrap it else: neutralObj = moose.Neutral(compartment.path+'/'+mechName) # Ion concentration pool if 'CaConc' == neutralObj.className: # wraps existing channel caconc = moose.CaConc(compartment.path+'/'+mechName) channel = None elif 'HHChannel2D' == neutralObj.className: ## HHChannel2D # wraps existing channel channel = moose.HHChannel2D(compartment.path+'/'+mechName) elif 'HHChannel' == neutralObj.className : ## HHChannel # wraps existing channel channel = moose.HHChannel(compartment.path+'/'+mechName) if name == 'Gbar': # if CaConc, neuroConstruct uses gbar for thickness or phi if channel is None: # If child Mstring 'phi' is present, set gbar as phi BUT, # value has been multiplied by Gfactor as a Gbar, SI or # physiological not known here, ignoring Gbar for CaConc, # instead of passing units here child = moose_utils.get_child_Mstring(caconc,'phi') if child is not None: #child.value = value pass else: #caconc.thick = value pass else: # if ion channel, usual Gbar channel.Gbar = value * math.pi * compartment.diameter \ * compartment.length elif name == 'Ek': channel.Ek = value # thick seems to be NEURON's extension to NeuroML level 2. elif name == 'thick': # JUST THIS WILL NOT DO - HAVE TO SET B based on this thick! caconc.thick = value # Later, when calling connect_CaConc, B is set for caconc based # on thickness of Ca shell and compartment l and dia. OR based # on the Mstring phi under CaConc path. if neuroml_utils.neuroml_debug: msg = "Setting {0} for {1} value {2}".format(name, compartment.path , value ) debug.printDebug("DEBUG", msg, frame=inspect.currentframe())
def readMorphML(self, cell, params={}, lengthUnits="micrometer"): """ returns {cellName:segDict} where segDict = { segid1 : [ segname , (proximalx,proximaly,proximalz) , (distalx,distaly,distalz),diameter,length,[potential_syn1, ... ] ] , ... } segname is "<name>_<segid>" because 1) guarantees uniqueness, 2) later scripts obtain segid from the compartment's name! """ debug.printDebug("DEBUG", "Entered function readMorphML") if lengthUnits in ['micrometer', 'micron']: self.length_factor = 1e-6 else: self.length_factor = 1.0 cellName = cell.attrib["name"] if cellName == 'LIF': self.mooseCell = moose.LeakyIaF(self.cellPath + '/' + cellName) self.segDict = {} else: # using moose Neuron class - in previous version 'Cell' class # Chaitanya. self.mooseCell = moose.Neuron(self.cellPath + '/' + cellName) self.cellDictBySegmentId[cellName] = [self.mooseCell, {}] self.cellDictByCableId[cellName] = [self.mooseCell, {}] self.segDict = {} # load morphology and connections between compartments Many neurons # exported from NEURON have multiple segments in a section Combine # those segments into one Compartment / section assume segments of # a compartment/section are in increasing order and assume all # segments of a compartment/section have the same cableid findall() # returns elements in document order: self.running_cableid = '' running_segid = '' segments = cell.findall(".//{" + self.mml + "}segment") segmentstotal = len(segments) for segnum, segment in enumerate(segments): self.addSegment(cellName, segnum, segment) # load cablegroups into a dictionary self.cablegroupsDict = {} # Two ways of specifying cablegroups in neuroml 1.x # <cablegroup>s with list of <cable>s cablegroups = cell.findall(".//{" + self.mml + "}cablegroup") for cablegroup in cablegroups: cablegroupname = cablegroup.attrib['name'] self.cablegroupsDict[cablegroupname] = [] for cable in cablegroup.findall(".//{" + self.mml + "}cable"): cableid = cable.attrib['id'] self.cablegroupsDict[cablegroupname].append(cableid) # <cable>s with list of <meta:group>s cables = cell.findall(".//{" + self.mml + "}cable") for cable in cables: cableid = cable.attrib['id'] cablegroups = cable.findall(".//{" + self.meta + "}group") for cablegroup in cablegroups: cablegroupname = cablegroup.text if cablegroupname in list(self.cablegroupsDict.keys()): self.cablegroupsDict[cablegroupname].append(cableid) else: self.cablegroupsDict[cablegroupname] = [cableid] # Add bioPhysics to the cell self.addBiophysics(cell, cellName) # load connectivity / synapses into the compartments connectivity = cell.find(".//{" + self.neuroml + "}connectivity") if connectivity is not None: self.addConnectivity(cell, cellName, connectivity) return {cellName: self.segDict}
def addParameterToCompartment(self, parameter, cell, options): """ Add parameter to compartment """ cellName = options['cellName'] mechName = options['mechName'] passive = options['passive'] paramName = parameter.attrib['name'] if passive: if paramName in ['gmax']: self.set_group_compartment_param( cell , cellName , parameter , 'RM' , self.RMfactor*1.0/float(parameter.attrib["value"]) , self.bio ) elif paramName in ['e','erev']: self.set_group_compartment_param( cell , cellName , parameter , 'Em' , self.Efactor*float(parameter.attrib["value"]) , self.bio ) elif paramName in ['inject']: self.set_group_compartment_param( cell , cellName , parameter , 'inject' , self.Ifactor*float(parameter.attrib["value"]) , self.bio ) else: msg = "Yo programmar of MorphML! You did not implemented" msg += " parameter {0} in mechanism {1} ".format( paramName , mechName ) debug.printDebug("WARN", msg, frame=inspect.currentframe()) else: if paramName in ['gmax']: gmaxval = float(eval( parameter.attrib["value"] ,{"__builtins__":None},{} ) ) self.set_group_compartment_param( cell , cellName , parameter , 'Gbar' , self.Gfactor*gmaxval , self.bio , mechName ) elif paramName in ['e','erev']: self.set_group_compartment_param( cell , cellName , parameter , 'Ek' , self.Efactor*float(parameter.attrib["value"]) , self.bio , mechName ) elif paramName in ['depth']: # has to be type Ion Concentration! self.set_group_compartment_param( cell , cellName , parameter , 'thick' , self.length_factor*float(parameter.attrib["value"]) , self.bio , mechName ) else: msg = "Yo programmar of MorphML! You did not implemented" msg += " parameter {0} in mechanism {1} ".format( paramName , mechName ) debug.printDebug("WARN", msg, frame=inspect.currentframe())
def readChannelML(self, channelElement, params={}, units="SI units"): """Loads a single channel """ # I first calculate all functions assuming a consistent system of units. # While filling in the A and B tables, I just convert to SI. Also # convert gmax and Erev. if 'Physiological Units' in units: # see pg 219 (sec 13.2) of Book of Genesis Vfactor = 1e-3 # V from mV Tfactor = 1e-3 # s from ms Gfactor = 1e1 # S/m^2 from mS/cm^2 concfactor = 1e6 # Mol = mol/m^-3 from mol/cm^-3 elif 'SI Units' in units: Vfactor = 1.0 Tfactor = 1.0 Gfactor = 1.0 concfactor = 1.0 else: debug.printDebug("ERR" , "wrong units %s. Existing... " % units , frame = inspect.currentframe() ) raise UserWarning, "Unknown units" # creates /library in MOOSE tree; elif present, wraps channel_name = channelElement.attrib['name'] if utils.neuroml_debug: msg = "Loading channel {} into {} ".format (channel_name, self.libraryPath) debug.printDebug("INFO", msg) IVrelation = channelElement.find( './{'+self.cml+'}current_voltage_relation' ) concdep = IVrelation.find('./{'+self.cml+'}conc_dependence') cPath = os.path.join(self.libraryPath, channel_name) if concdep is None: channel = moose.HHChannel(cPath) else: channel = moose.HHChannel2D(cPath) if IVrelation.attrib['cond_law'] == "ohmic": channel.Gbar = float(IVrelation.attrib['default_gmax']) * Gfactor channel.Ek = float(IVrelation.attrib['default_erev']) * Vfactor channelIon = moose.Mstring(channel.path+'/ion') channelIon.value = IVrelation.attrib['ion'] if concdep is not None: channelIonDependency = moose.Mstring( channel.path + '/ionDependency' ) channelIonDependency.value = concdep.attrib['ion'] nernstnote = IVrelation.find('./{'+utils.meta_ns+'}notes') if nernstnote is not None: # the text in nernstnote is "Nernst,Cout=<float>,z=<int>" nernst_params = string.split(nernstnote.text,',') if nernst_params[0] == 'Nernst': nernstMstring = moose.Mstring(channel.path+'/nernst_str') nernstMstring.value = str( float(string.split(nernst_params[1],'=')[1]) * concfactor ) + ',' + str(int(string.split(nernst_params[2],'=')[1])) gates = IVrelation.findall('./{'+self.cml+'}gate') if len(gates) > 3: msg = "Sorry! Maximum x, y, and z (three) gates are possible in\ MOOSE/Genesis" debug.printDebug("ERR", msg, frame=inspect.currentframe()) raise UserWarning, "Bad value or parameter" # These are the names that MOOSE uses to create gates. gate_full_name = [ 'gateX', 'gateY', 'gateZ' ] # if impl_prefs tag is present change VMIN, VMAX and NDIVS impl_prefs = channelElement.find('./{'+self.cml+'}impl_prefs') if impl_prefs is not None: table_settings = impl_prefs.find('./{'+self.cml+'}table_settings') # some problem here... disable VMIN_here = float(table_settings.attrib['min_v']) VMAX_here = float(table_settings.attrib['max_v']) NDIVS_here = int(table_settings.attrib['table_divisions']) dv_here = (VMAX_here - VMIN_here) / NDIVS_here else: # default VMIN, VMAX and dv are in SI convert them to current # calculation units used by channel definition while loading into # tables, convert them back to SI VMIN_here = utils.VMIN/Vfactor VMAX_here = utils.VMAX/Vfactor NDIVS_here = utils.NDIVS dv_here = utils.dv/Vfactor offset = IVrelation.find('./{'+self.cml+'}offset') if offset is None: vNegOffset = 0.0 else: vNegOffset = float(offset.attrib['value']) self.parameters = [] for parameter in channelElement.findall('.//{'+self.cml+'}parameter'): self.parameters.append((parameter.attrib['name'] , float(parameter.attrib['value'])) ) for num,gate in enumerate(gates): # if no q10settings tag, the q10factor remains 1.0 if present but no # gate attribute, then set q10factor if there is a gate attribute, # then set it only if gate attrib matches gate name self.q10factor = 1.0 self.gate_name = gate.attrib['name'] q10sets = IVrelation.findall('./{'+self.cml+'}q10_settings') for q10settings in q10sets: # self.temperature from neuro.utils if 'gate' in list(q10settings.attrib.keys()): if q10settings.attrib['gate'] == self.gate_name: self.setQ10(q10settings) break else: self.setQ10(q10settings) # HHChannel2D crashing on setting Xpower! temperamental! If you # print something before, it gives cannot creategate from copied # channel, else crashes Setting power first. This is necessary # because it also initializes the gate's internal data structures as # a side effect. Alternatively, gates can be initialized explicitly # by calling HHChannel.createGate(). gate_power = float( gate.get( 'instances' ) ) if num == 0: channel.Xpower = gate_power if concdep is not None: channel.Xindex = "VOLT_C1_INDEX" elif num == 1: channel.Ypower = gate_power if concdep is not None: channel.Yindex = "VOLT_C1_INDEX" elif num == 2: channel.Zpower = gate_power if concdep is not None: channel.Zindex = "VOLT_C1_INDEX" ## Getting handle to gate using the gate's path. gate_path = os.path.join(channel.path, gate_full_name[ num ]) if concdep is None: moosegate = moose.HHGate( gate_path ) # set SI values inside MOOSE moosegate.min = VMIN_here*Vfactor moosegate.max = VMAX_here*Vfactor moosegate.divs = NDIVS_here ## V.IMP to get smooth curves, else even with 3000 divisions ## there are sudden transitions. moosegate.useInterpolation = True else: moosegate = moose.HHGate2D( gate_path ) # If alpha and beta functions exist, make them here for transition in gate.findall('./{'+self.cml+'}transition'): # make python functions with names of transitions... fn_name = transition.attrib['name'] # I assume that transitions if present are called alpha and beta # for forwand backward transitions... if fn_name in ['alpha','beta']: self.make_cml_function(transition, fn_name, concdep) else: debug.printDebug("ERROR" , "Unsupported transition {0}".format(fn_name) ) sys.exit() time_course = gate.find('./{'+self.cml+'}time_course') # tau is divided by self.q10factor in make_function() thus, it gets # divided irrespective of <time_course> tag present or not. if time_course is not None: self.make_cml_function(time_course, 'tau', concdep) steady_state = gate.find('./{'+self.cml+'}steady_state') if steady_state is not None: self.make_cml_function(steady_state, 'inf', concdep) if concdep is None: ca_name = '' # no Ca dependence else: # Ca dependence ca_name = ','+concdep.attrib['variable_name'] # Create tau() and inf() if not present, from alpha() and beta() for fn_element,fn_name,fn_expr in [ (time_course,'tau',"1/(alpha+beta)") , (steady_state,'inf',"alpha/(alpha+beta)") ]: # put in args for alpha and beta, could be v and Ca dep. expr_string = self.replace(fn_expr , 'alpha' , 'self.alpha(v'+ca_name+')' ) expr_string = self.replace(expr_string , 'beta' , 'self.beta(v'+ca_name+')' ) # if time_course/steady_state are not present, then alpha annd # beta transition elements should be present, and fns created. if fn_element is None: self.make_function( fn_name ,'generic' , expr_string = expr_string , concdep=concdep ) # non Ca dependent channel if concdep is None: # while calculating, use the units used in xml defn, while # filling in table, I convert to SI units. v0 = VMIN_here - vNegOffset n_entries = NDIVS_here + 1 tableA = [0.0] * n_entries tableB = [0.0] * n_entries for i in range(n_entries): v = v0 + (i * dv_here) inf = self.inf(v) tau = self.tau(v) # convert to SI before writing to table # qfactor is already in inf and tau tableA[i] = (inf / tau) / Tfactor tableB[i] = (1.0 / tau) / Tfactor moosegate.tableA = tableA moosegate.tableB = tableB ## Ca dependent channel else: # UNITS: while calculating, use the units used in xml defn, # while filling in table, I convert to SI units. Note here Ca # units do not enter, but units of CaMIN, CaMAX and ca_conc in # fn expr should match. v = VMIN_here - vNegOffset CaMIN = float(concdep.attrib['min_conc']) CaMAX = float(concdep.attrib['max_conc']) CaNDIVS = 100 dCa = (CaMAX-CaMIN)/CaNDIVS # CAREFUL!: tableA = [[0.0]*(CaNDIVS+1)]*(NDIVS_here+1) will not # work! * does a shallow copy, same list will get repeated 200 # times! Thus setting tableA[35][1] = 5.0 will set all rows, # 1st col to 5.0!!!! tableA = [[0.0]*(CaNDIVS+1) for i in range(NDIVS_here+1)] tableB = [[0.0]*(CaNDIVS+1) for i in range(NDIVS_here+1)] for i in range(NDIVS_here + 1): Ca = CaMIN for j in range(CaNDIVS + 1): inf = self.inf(v, Ca) tau = self.tau(v, Ca) # convert to SI (Tfactor) before writing to table # qfactor is already in inf and tau tableA[i][j] = (inf / tau) / Tfactor tableB[i][j] = (1.0 / tau) / Tfactor Ca += dCa v += dv_here # Presently HHGate2D doesn't allow the setting of tables as 2D # vectors directly #moosegate.tableA = tableA #moosegate.tableB = tableB # Instead, I wrap the interpol2D objects inside HHGate2D and set # the tables moosegate_tableA = moose.Interpol2D(moosegate.path+'/tableA') # set SI values inside MOOSE moosegate_tableA.xmin = VMIN_here*Vfactor moosegate_tableA.xmax = VMAX_here*Vfactor moosegate_tableA.xdivs = NDIVS_here #moosegate_tableA.dx = dv_here*Vfactor moosegate_tableA.ymin = CaMIN*concfactor moosegate_tableA.ymax = CaMAX*concfactor moosegate_tableA.ydivs = CaNDIVS #moosegate_tableA.dy = dCa*concfactor moosegate_tableA.tableVector2D = tableA moosegate_tableB = moose.Interpol2D(moosegate.path+'/tableB') ## set SI values inside MOOSE moosegate_tableB.xmin = VMIN_here*Vfactor moosegate_tableB.xmax = VMAX_here*Vfactor moosegate_tableB.xdivs = NDIVS_here #moosegate_tableB.dx = dv_here*Vfactor moosegate_tableB.ymin = CaMIN*concfactor moosegate_tableB.ymax = CaMAX*concfactor moosegate_tableB.ydivs = CaNDIVS #moosegate_tableB.dy = dCa*concfactor moosegate_tableB.tableVector2D = tableB