diff --git a/python/moose/neuroml2/README b/python/moose/neuroml2/README index c024486979..4f6d4d7219 100644 --- a/python/moose/neuroml2/README +++ b/python/moose/neuroml2/README @@ -1,3 +1,19 @@ +Update 2021-10-28 Padraig Gleeson + +reader.py updated to work with Python 3. + +To test, run: + + python run_cell.py # example of a passive cell + python run_hhcell.py # example of a HH cell + +Note: older test_*.py files are still giving errors, but may be out of date + + +=============================== + +Previous status: + NeuroML2 is a moving target and the current parser was generated from the schema publicly available on Jul 28 10:18:38 2013 using the generateDS.py module. @@ -18,4 +34,4 @@ The other python files in this directory were hand-coded. So you may need to tweak them in case NeuroML2 has some incompatible changes or adds new types. -- Subhasis Ray, 2016-04-17 \ No newline at end of file +- Subhasis Ray, 2016-04-17 diff --git a/python/moose/neuroml2/__init__.py b/python/moose/neuroml2/__init__.py index 92baa3ae34..d24c6492a2 100644 --- a/python/moose/neuroml2/__init__.py +++ b/python/moose/neuroml2/__init__.py @@ -61,7 +61,7 @@ import moose.utils as mu __author__ = 'Subhasis Ray' +from moose.neuroml2.reader import NML2Reader -from .reader import NML2Reader # __init__.py ends here diff --git a/python/moose/neuroml2/reader.py b/python/moose/neuroml2/reader.py index 8140e8c536..9490a61b7d 100644 --- a/python/moose/neuroml2/reader.py +++ b/python/moose/neuroml2/reader.py @@ -4,13 +4,11 @@ # Description: NeuroML2 reader. # Implementation of reader for NeuroML 2 models. # TODO: handle morphologies of more than one segment... -# # Author: Subhasis Ray, Padraig Gleeson -# Maintainer: Dilawar Singh +# Maintainer: Dilawar Singh , Padraig Gleeson # Created: Wed Jul 24 15:55:54 2013 (+0530) -# -# Notes: -# For update/log, please see git-blame documentation or browse the github +# Notes: +# For update/log, please see git-blame documentation or browse the github # repo https://github.com/BhallaLab/moose-core import os @@ -47,7 +45,7 @@ def _gates_sorted( all_gates ): Notes ----- - If the id of gates are subset of 'x', 'y' or 'z' then sort them so they load in + If the id of gates are subset of 'x', 'y' or 'z' then sort them so they load in X, Y or Z gate respectively. Otherwise do not touch them i.e. first gate will be loaded into X, second into Y and so on. """ @@ -74,7 +72,7 @@ def _isConcDep(ct): dependant on voltage. :param ct: ComponentType - :type ct: nml.ComponentType + :type ct: nml.ComponentType :return: True if Component is depenant on conc, False otherwise. """ @@ -85,7 +83,7 @@ def _isConcDep(ct): def _findCaConcVariableName(): """_findCaConcVariableName Find a suitable CaConc for computing HHGate tables. - This is a hack, though it is likely to work in most cases. + This is a hack, though it is likely to work in most cases. """ caConcs = moose.wildcardFind( '/library/##[TYPE=CaConc]' ) assert len(caConcs) >= 1, "No moose.CaConc found. Currently moose \ @@ -104,11 +102,11 @@ def sarea(comp): if comp.length > 0: return math.pi * comp.diameter * comp.length else: - return math.pi * comp.diameter * comp.diameter + return math.pi * comp.diameter * comp.diameter def xarea(compt): """xarea - Return the cross sectional area (𝜋r²) from the diameter of the compartment. + Return the cross sectional area (𝜋r²) from the diameter of the compartment. Note: ---- @@ -126,7 +124,7 @@ def setRa(comp, resistivity): if comp.length > 0: comp.Ra = resistivity * comp.length / xarea(comp) else: - comp.Ra = resistivity * 8.0 / (comp.diameter * np.pi) + comp.Ra = resistivity * 4.0 / (comp.diameter * np.pi) def setRm(comp, condDensity): """Set membrane resistance""" @@ -141,7 +139,7 @@ def getSegments(nmlcell, component, sg_to_segments): sg = component.segment_groups if sg is None: segments = nmlcell.morphology.segments - elif sg == 'all': + elif sg == 'all': segments = [seg for seglist in sg_to_segments.values() for seg in seglist] else: segments = sg_to_segments[sg] @@ -149,7 +147,7 @@ def getSegments(nmlcell, component, sg_to_segments): class NML2Reader(object): - """Reads NeuroML2 and creates MOOSE model. + """Reads NeuroML2 and creates MOOSE model. NML2Reader.read(filename) reads an NML2 model under `/library` with the toplevel name defined in the NML2 file. @@ -169,8 +167,11 @@ def __init__(self, verbose=False): if self.verbose: logger_.setLevel( logging.DEBUG ) self.doc = None - self.filename = None - self.nml_to_moose = {} # NeuroML object to MOOSE object + self.filename = None + self.nml_cells_to_moose = {} # NeuroML object to MOOSE object + self.nml_segs_to_moose = {} # NeuroML object to MOOSE object + self.nml_chans_to_moose = {} # NeuroML object to MOOSE object + self.nml_conc_to_moose = {} # NeuroML object to MOOSE object self.moose_to_nml = {} # Moose object to NeuroML object self.proto_cells = {} # map id to prototype cell in moose self.proto_chans = {} # map id to prototype channels in moose @@ -181,7 +182,7 @@ def __init__(self, verbose=False): self.id_to_ionChannel = {} self._cell_to_sg = {} # nml cell to dict - the dict maps segment groups to segments self._variables = {} - + self.cells_in_populations = {} self.pop_to_cell_type = {} self.seg_id_to_comp_name = {} @@ -190,30 +191,30 @@ def __init__(self, verbose=False): def read(self, filename, symmetric=True): filename = os.path.realpath( filename ) - self.doc = nml.loaders.read_neuroml2_file( + self.doc = nml.loaders.read_neuroml2_file( filename, include_includes=True, verbose=self.verbose) - + self.filename = filename - logger_.info('Parsed NeuroML2 file: %s'% filename) + logger_.info('Parsed the NeuroML2 file: %s'% filename) if self.verbose: _write_flattened_nml( self.doc, '%s__flattened.xml' % self.filename ) - + if len(self.doc.networks)>=1: self.network = self.doc.networks[0] moose.celsius = self._getTemperature() - + self.importConcentrationModels(self.doc) self.importIonChannels(self.doc) self.importInputs(self.doc) - + for cell in self.doc.cells: self.createCellPrototype(cell, symmetric=symmetric) - + if len(self.doc.networks)>=1: self.createPopulations() self.createInputs() - + def _getTemperature(self): if self.network is not None: if self.network.type=="networkWithTemperature": @@ -222,31 +223,31 @@ def _getTemperature(self): # Why not, if there's no temp dependence in nml..? return 0 return SI('25') - + def getCellInPopulation(self, pop_id, index): return self.cells_in_populations[pop_id][index] - + def getComp(self, pop_id, cellIndex, segId): return moose.element('%s/%s/%s/%s' % ( self.lib.path, pop_id, cellIndex , self.seg_id_to_comp_name[self.pop_to_cell_type[pop_id]][segId]) ) - + def createPopulations(self): for pop in self.network.populations: ep = '%s/%s' % (self.lib.path, pop.id) mpop = moose.element(ep) if moose.exists(ep) else moose.Neutral(ep) self.cells_in_populations[pop.id] ={} for i in range(pop.size): - logger_.info("Creating %s/%s instances of %s under %s"%(i,pop.size,pop.component, mpop)) + logger_.info("Creating %s/%s instances of cell: %s under %s"%(i,pop.size,pop.component, mpop)) self.pop_to_cell_type[pop.id]=pop.component chid = moose.copy(self.proto_cells[pop.component], mpop, '%s'%(i)) self.cells_in_populations[pop.id][i]=chid - - + + def getInput(self, input_id): return moose.element('%s/inputs/%s'%(self.lib.path,input_id)) - - + + def createInputs(self): for el in self.network.explicit_inputs: pop_id = el.target.split('[')[0] @@ -256,21 +257,21 @@ def createInputs(self): seg_id = el.target.split('/')[1] input = self.getInput(el.input) moose.connect(input, 'output', self.getComp(pop_id,i,seg_id), 'injectMsg') - + for il in self.network.input_lists: for ii in il.input: input = self.getInput(il.component) moose.connect(input, 'output' - , self.getComp(il.populations,ii.get_target_cell__hash(),ii.get_segment__hash()) + , self.getComp(il.populations,ii.get_target_cell_id(),ii.get_segment_id()) , 'injectMsg') - + def createCellPrototype(self, cell, symmetric=True): """To be completed - create the morphology, channels in prototype""" ep = '%s/%s' % (self.lib.path, cell.id) nrn = moose.element(ep) if moose.exists(ep) else moose.Neuron(ep) self.proto_cells[cell.id] = nrn - self.nml_to_moose[cell.id] = nrn + self.nml_cells_to_moose[cell.id] = nrn self.moose_to_nml[nrn] = cell self.createMorphology(cell, nrn, symmetric=symmetric) self.importBiophysics(cell, nrn) @@ -285,7 +286,7 @@ def createMorphology(self, nmlcell, moosecell, symmetric=True): """ morphology = nmlcell.morphology segments = morphology.segments - id_to_segment = dict([(seg.id, seg) for seg in segments]) + id_to_segment = dict([(seg.id, seg) for seg in segments]) if symmetric: compclass = moose.SymCompartment else: @@ -317,8 +318,8 @@ def createMorphology(self, nmlcell, moosecell, symmetric=True): except AttributeError: parent = None self.moose_to_nml[comp] = segment - self.nml_to_moose[segment.id] = comp - p0 = segment.proximal + self.nml_segs_to_moose[segment.id] = comp + p0 = segment.proximal if p0 is None: if parent: p0 = parent.distal @@ -339,7 +340,7 @@ def createMorphology(self, nmlcell, moosecell, symmetric=True): if parent: pcomp = id_to_comp[parent.id] moose.connect(comp, src, pcomp, dst) - sg_to_segments = {} + sg_to_segments = {} for sg in morphology.segment_groups: sg_to_segments[sg.id] = [id_to_segment[m.segments] for m in sg.members] for sg in morphology.segment_groups: @@ -348,10 +349,10 @@ def createMorphology(self, nmlcell, moosecell, symmetric=True): for inc in sg.includes: for cseg in sg_to_segments[inc.segment_groups]: sg_to_segments[sg.id].append(cseg) - + if not 'all' in sg_to_segments: sg_to_segments['all'] = [ s for s in segments ] - + self._cell_to_sg[nmlcell.id] = sg_to_segments return id_to_comp, id_to_segment, sg_to_segments @@ -378,16 +379,16 @@ def importCapacitances(self, nmlcell, moosecell, specificCapacitances): for specific_cm in specificCapacitances: cm = SI(specific_cm.value) for seg in sg_to_segments[specific_cm.segment_groups]: - comp = self.nml_to_moose[seg.id] + comp = self.nml_segs_to_moose[seg.id] comp.Cm = sarea(comp) * cm - + def importInitMembPotential(self, nmlcell, moosecell, membraneProperties): sg_to_segments = self._cell_to_sg[nmlcell.id] for imp in membraneProperties.init_memb_potentials: initv = SI(imp.value) for seg in sg_to_segments[imp.segment_groups]: - comp = self.nml_to_moose[seg.id] - comp.initVm = initv + comp = self.nml_segs_to_moose[seg.id] + comp.initVm = initv def importIntracellularProperties(self, nmlcell, moosecell, properties): self.importAxialResistance(nmlcell, properties) @@ -398,14 +399,14 @@ def importSpecies(self, nmlcell, properties): for species in properties.species: # Developer note: Not sure if species.concentration_model should be # a nml element of just plain string. I was getting plain text from - # nml file here. + # nml file here. concModel = species.concentration_model if (concModel is not None) and (concModel not in self.proto_pools): logger_.warn("No concentrationModel '%s' found."%concModel) continue segments = getSegments(nmlcell, species, sg_to_segments) for seg in segments: - comp = self.nml_to_moose[seg.id] + comp = self.nml_segs_to_moose[seg.id] self.copySpecies(species, comp) def copySpecies(self, species, compartment): @@ -426,8 +427,8 @@ def copySpecies(self, species, compartment): raise RuntimeError(msg) pool_id = moose.copy(proto_pool, compartment, species.id) pool = moose.element(pool_id) - pool.B = pool.B / (np.pi * compartment.length * ( - 0.5 * compartment.diameter + pool.thick) * + pool.B = pool.B / (np.pi * compartment.length * ( + 0.5 * compartment.diameter + pool.thick) * (0.5 * compartment.diameter - pool.thick) ) return pool @@ -437,9 +438,9 @@ def importAxialResistance(self, nmlcell, intracellularProperties): for r in intracellularProperties.resistivities: segments = getSegments(nmlcell, r, sg_to_segments) for seg in segments: - comp = self.nml_to_moose[seg.id] - setRa(comp, SI(r.value)) - + comp = self.nml_segs_to_moose[seg.id] + setRa(comp, SI(r.value)) + def isPassiveChan(self,chan): if chan.type == 'ionChannelPassive': return True @@ -450,16 +451,19 @@ def isPassiveChan(self,chan): def evaluate_moose_component(self, ct, variables): print( "[INFO ] Not implemented." ) return False - + def calculateRateFn(self, ratefn, vmin, vmax, tablen=3000, vShift='0mV'): """Returns A / B table from ngate.""" - from . import hhfit + from moose.neuroml2.hhfit import exponential2 + from moose.neuroml2.hhfit import sigmoid2 + from moose.neuroml2.hhfit import linoid2 + from moose.neuroml2.units import SI rate_fn_map = { - 'HHExpRate': hhfit.exponential2, - 'HHSigmoidRate': hhfit.sigmoid2, - 'HHSigmoidVariable': hhfit.sigmoid2, - 'HHExpLinearRate': hhfit.linoid2 + 'HHExpRate': exponential2, + 'HHSigmoidRate': sigmoid2, + 'HHSigmoidVariable': sigmoid2, + 'HHExpLinearRate': linoid2 } tab = np.linspace(vmin, vmax, tablen) @@ -505,22 +509,22 @@ def importChannelsToCell(self, nmlcell, moosecell, membrane_properties): try: ionChannel = self.id_to_ionChannel[chdens.ion_channel] except KeyError: - logger_.info('No channel with id: %s' % chdens.ion_channel) + logger_.info('No channel with id: %s' % chdens.ion_channel) continue - + if self.verbose: logger_.info('Setting density of channel %s in %s to %s; erev=%s (passive: %s)'%( chdens.id, segments, condDensity,erev,self.isPassiveChan(ionChannel)) ) - + if self.isPassiveChan(ionChannel): for seg in segments: - # comp = self.nml_to_moose[seg] - setRm(self.nml_to_moose[seg.id], condDensity) - setEk(self.nml_to_moose[seg.id], erev) + comp = self.nml_segs_to_moose[seg.id] + setRm(comp, condDensity) + setEk(comp, erev) else: for seg in segments: - self.copyChannel(chdens, self.nml_to_moose[seg.id], condDensity, erev) + self.copyChannel(chdens, self.nml_segs_to_moose[seg.id], condDensity, erev) '''moose.le(self.nml_to_moose[seg]) moose.showfield(self.nml_to_moose[seg], field="*", showtype=True)''' @@ -541,21 +545,19 @@ def copyChannel(self, chdens, comp, condDensity, erev): raise Exception('No prototype channel for %s referred to by %s' % (chdens.ion_channel, chdens.id)) if self.verbose: - logger_.info('Copying %s to %s, %s; erev=%s'%(chdens.id, comp, condDensity, erev)) + logger_.info('Copying the %s to %s, %s; erev=%s'%(chdens.id, comp, condDensity, erev)) orig = chdens.id chid = moose.copy(proto_chan, comp, chdens.id) chan = moose.element(chid) - - # We are updaing the keys() here. Need copy: using list(keys()) to - # create a copy. - for p in list(self.paths_to_chan_elements.keys()): + els = list(self.paths_to_chan_elements.keys()) + for p in els: pp = p.replace('%s/'%chdens.ion_channel,'%s/'%orig) self.paths_to_chan_elements[pp] = self.paths_to_chan_elements[p].replace('%s/'%chdens.ion_channel,'%s/'%orig) #logger_.info(self.paths_to_chan_elements) chan.Gbar = sarea(comp) * condDensity chan.Ek = erev moose.connect(chan, 'channel', comp, 'channel') - return chan + return chan def _is_standard_nml_rate(self, rate): return rate.type=='HHExpLinearRate' \ @@ -567,7 +569,7 @@ def createHHChannel(self, chan, vmin=-150e-3, vmax=100e-3, vdivs=5000): mchan = moose.HHChannel('%s/%s' % (self.lib.path, chan.id)) mgates = [moose.element(x) for x in [mchan.gateX, mchan.gateY, mchan.gateZ]] assert len(chan.gate_hh_rates)<=3, "We handle only up to 3 gates in HHCHannel" - + if self.verbose: logger_.info('== Creating channel: %s (%s) -> %s (%s)'%(chan.id, chan.gate_hh_rates, mchan, mgates)) @@ -607,14 +609,14 @@ def createHHChannel(self, chan, vmin=-150e-3, vmax=100e-3, vdivs=5000): , (self._getTemperature()- SI(ngate.q10_settings.experimental_temp))/10 ) else: - raise Exception('Unknown Q10 scaling type %s: %s'%( + raise Exception('Unknown Q10 scaling type %s: %s'%( ngate.q10_settings.type,ngate.q10_settings) ) - - logger_.debug('+ Gate: %s; %s; %s; %s; %s; scale=%s'% ( + + logger_.debug('+ Gate: %s; %s; %s; %s; %s; scale=%s'% ( ngate.id, mgate.path, mchan.Xpower, fwd, rev, q10_scale) ) - + if (fwd is not None) and (rev is not None): alpha = self.calculateRateFn(fwd, vmin, vmax, vdivs) beta = self.calculateRateFn(rev, vmin, vmax, vdivs) @@ -631,7 +633,7 @@ def createHHChannel(self, chan, vmin=-150e-3, vmax=100e-3, vdivs=5000): inf = self.calculateRateFn(inf, vmin, vmax, vdivs) mgate.tableA = q10_scale * (inf / tau) mgate.tableB = q10_scale * (1 / tau) - + if hasattr(ngate,'steady_state') and (ngate.time_course is None) and (ngate.steady_state is not None): inf = ngate.steady_state tau = 1 / (alpha + beta) @@ -640,7 +642,7 @@ def createHHChannel(self, chan, vmin=-150e-3, vmax=100e-3, vdivs=5000): if len(inf) > 0: mgate.tableA = q10_scale * (inf / tau) mgate.tableB = q10_scale * (1 / tau) - + logger_.info('%s: Created %s for %s'%(self.filename,mchan.path,chan.id)) return mchan @@ -667,11 +669,11 @@ def importInputs(self, doc): pg.firstWidth = SI(pg_nml.duration) pg.firstLevel = SI(pg_nml.amplitude) pg.secondDelay = 1e9 - + def importIonChannels(self, doc, vmin=-150e-3, vmax=100e-3, vdivs=5000): logger_.info('%s: Importing the ion channels' % self.filename ) - + for chan in doc.ion_channel+doc.ion_channel_hhs: if chan.type == 'ionChannelHH': mchan = self.createHHChannel(chan) @@ -679,11 +681,11 @@ def importIonChannels(self, doc, vmin=-150e-3, vmax=100e-3, vdivs=5000): mchan = self.createPassiveChannel(chan) else: mchan = self.createHHChannel(chan) - + self.id_to_ionChannel[chan.id] = chan - self.nml_to_moose[chan.id] = mchan + self.nml_chans_to_moose[chan.id] = mchan self.proto_chans[chan.id] = mchan - logger_.info(self.filename + ': Created ion channel %s for %s %s'%( + logger_.info(self.filename + ': Created ion channel %s for %s %s'%( mchan.path, chan.type, chan.id)) def importConcentrationModels(self, doc): @@ -691,7 +693,7 @@ def importConcentrationModels(self, doc): self.createDecayingPoolConcentrationModel(concModel) def createDecayingPoolConcentrationModel(self, concModel): - """Create prototype for concentration model""" + """Create prototype for concentration model""" if hasattr(concModel, 'name') and concModel.name is not None: name = concModel.name else: @@ -701,10 +703,10 @@ def createDecayingPoolConcentrationModel(self, concModel): ca.CaBasal = SI(concModel.resting_conc) ca.tau = SI(concModel.decay_constant) ca.thick = SI(concModel.shell_thickness) - ca.B = 5.2e-6 # B = 5.2e-6/(Ad) where A is the area of the - # shell and d is thickness - must divide by + ca.B = 5.2e-6 # B = 5.2e-6/(Ad) where A is the area of the + # shell and d is thickness - must divide by # shell volume when copying self.proto_pools[concModel.id] = ca - self.nml_to_moose[name] = ca + self.nml_concs_to_moose[concModel.id] = ca self.moose_to_nml[ca] = concModel logger_.debug('Created moose element: %s for nml conc %s' % (ca.path, concModel.id)) diff --git a/python/moose/neuroml2/run_cell.py b/python/moose/neuroml2/run_cell.py index 81d535f1eb..a72af29a6c 100644 --- a/python/moose/neuroml2/run_cell.py +++ b/python/moose/neuroml2/run_cell.py @@ -45,48 +45,48 @@ import moose import moose.utils as mu import sys -from reader import NML2Reader +from moose.neuroml2.reader import NML2Reader import numpy as np - + def run(nogui): - + reader = NML2Reader(verbose=True) filename = 'test_files/passiveCell.nml' print('Loading: %s'%filename) reader.read(filename) - - + + msoma = reader.getComp(reader.doc.networks[0].populations[0].id,0,0) print(msoma) - - + + data = moose.Neutral('/data') - + pg = reader.getInput('pulseGen1') - + inj = moose.Table('%s/pulse' % (data.path)) moose.connect(inj, 'requestOut', pg, 'getOutputValue') - - + + vm = moose.Table('%s/Vm' % (data.path)) moose.connect(vm, 'requestOut', msoma, 'getVm') - + simdt = 1e-6 plotdt = 1e-4 simtime = 150e-3 - + for i in range(8): moose.setClock( i, simdt ) moose.setClock( 8, plotdt ) moose.reinit() moose.start(simtime) - + print("Finished simulation!") - + t = np.linspace(0, simtime, len(vm.vector)) - + if not nogui: import matplotlib.pyplot as plt @@ -103,9 +103,9 @@ def run(nogui): plt.show() plt.close() - + if __name__ == '__main__': - + nogui = '-nogui' in sys.argv - + run(nogui) diff --git a/python/moose/neuroml2/run_hhcell.py b/python/moose/neuroml2/run_hhcell.py index fb92841ded..b5d37b0268 100644 --- a/python/moose/neuroml2/run_hhcell.py +++ b/python/moose/neuroml2/run_hhcell.py @@ -44,7 +44,7 @@ import moose import sys -from reader import NML2Reader +from moose.neuroml2.reader import NML2Reader import numpy as np @@ -60,63 +60,63 @@ def test_channel_gates(): h = moose.element('/library[0]/naChan[0]/gateY') n = moose.element('/library[0]/kChan[0]/gateX') v = np.linspace(n.min,n.max, n.divs+1) - + plt.subplot(221) plt.plot(v, 1/m.tableB, label='tau_m') plt.plot(v, 1/h.tableB, label='tau_h') plt.plot(v, 1/n.tableB, label='tau_n') plt.legend() - + plt.subplot(222) plt.plot(v, m.tableA/m.tableB, label='m_inf') plt.plot(v, h.tableA/h.tableB, label='h_inf') plt.plot(v, n.tableA/n.tableB, label='n_inf') plt.legend() - + plt.subplot(223) plt.plot(v, m.tableA, label='mA(alpha)') plt.plot(v, h.tableA, label='hA(alpha)') plt.plot(v, n.tableA, label='nA(alpha)') plt.legend() plt.subplot(224) - + plt.plot(v, m.tableB, label='mB') plt.plot(v, m.tableB-m.tableA, label='mB-A(beta)') - + plt.plot(v, h.tableB, label='hB') plt.plot(v, h.tableB-h.tableA, label='hB-A(beta)') - + plt.plot(v, n.tableB, label='nB') plt.plot(v, n.tableB-n.tableA, label='nB-nA(beta)') plt.legend() - + plt.show() def run(nogui): - + reader = NML2Reader(verbose=True) filename = 'test_files/NML2_SingleCompHHCell.nml' print('Loading: %s'%filename) reader.read(filename, symmetric=True) - - + + msoma = reader.getComp(reader.doc.networks[0].populations[0].id,0,0) print(msoma) - - + + data = moose.Neutral('/data') - + pg = reader.getInput('pulseGen1') - + inj = moose.Table('%s/pulse' % (data.path)) moose.connect(inj, 'requestOut', pg, 'getOutputValue') - - + + vm = moose.Table('%s/Vm' % (data.path)) moose.connect(vm, 'requestOut', msoma, 'getVm') - + simdt = 1e-6 plotdt = 1e-4 simtime = 300e-3 @@ -126,11 +126,11 @@ def run(nogui): moose.setClock( 8, plotdt ) moose.reinit() moose.start(simtime) - + print("Finished simulation!") - + t = np.linspace(0, simtime, len(vm.vector)) - + if not nogui: import matplotlib.pyplot as plt @@ -153,11 +153,10 @@ def run(nogui): test_channel_gates() plt.show() plt.close() - - + + if __name__ == '__main__': - + nogui = '-nogui' in sys.argv - + run(nogui) - diff --git a/python/moose/neuroml2/test_reader.py b/python/moose/neuroml2/test_reader.py index 53d420d853..433eadb5cd 100644 --- a/python/moose/neuroml2/test_reader.py +++ b/python/moose/neuroml2/test_reader.py @@ -52,17 +52,20 @@ import moose import neuroml as nml from reader import NML2Reader +import os class TestFullCell(unittest.TestCase): def setUp(self): + if '/library' in moose.le(): + moose.delete('/library') self.reader = NML2Reader(verbose=True) self.lib = moose.Neutral('/library') - self.filename = 'test_files/NML2_FullCell.nml' + self.filename = os.path.realpath('test_files/NML2_FullCell.nml') self.reader.read(self.filename) - for ncell in self.reader.nml_to_moose: - if isinstance(ncell, nml.Cell): - self.ncell = ncell + for ncell in self.reader.nml_cells_to_moose: + if self.reader.nml_cells_to_moose[ncell].isA("Neuron"): + self.ncell = self.reader.nml_cells_to_moose[ncell] break self.mcell = moose.element('/library/SpikingCell') self.soma = moose.element(self.mcell.path + '/Soma') @@ -75,8 +78,8 @@ def test_basicLoading(self): self.assertIsNotNone(self.reader.doc, 'doc is None') def test_createCellPrototype(self): - self.assertIsInstance(self.mcell, moose.Neuron) - self.assertEqual(self.mcell.name, self.ncell.id) + self.assertEqual(moose.element(self.mcell).className, 'Neuron') + self.assertEqual(moose.element(self.mcell).name, self.ncell.name) def test_createMorphology(self): for comp_id in moose.wildcardFind(self.mcell.path + '/##[ISA=Compartment]'): @@ -94,18 +97,14 @@ def test_createMorphology(self): def test_connectivity(self): """Test raxial-axial connectivity between MOOSE compartments when there is parent->child relation in NML2.""" - id_to_seg = dict([(seg.id, seg) for seg in self.ncell.morphology.segments]) - for seg in self.ncell.morphology.segments: - try: - pseg = id_to_seg[seg.parent.segment] - except AttributeError: - continue - comp = self.reader.nml_to_moose[seg] - pcomp = self.reader.nml_to_moose[pseg] - - ''' - TODO: what should this be updated to??? - self.assertIn(comp.id_, pcomp.neighbours['raxial'])''' + msgs_soma = self.soma.msgIn + msgs_dendrite1 = self.dendrite1.msgIn + msgs_dendrite2 = self.dendrite2.msgIn + + self.assertEqual(msgs_soma[3].e1.name, self.dendrite1.name) + self.assertEqual(msgs_dendrite1[3].e1.name, self.dendrite2.name) + self.assertEqual(msgs_dendrite2[3].e1.name, self.spine1.name) + def test_capacitance(self): for comp_id in moose.wildcardFind(self.mcell.path + '/##[ISA=Compartment]'): @@ -114,7 +113,7 @@ def test_capacitance(self): self.assertTrue((comp.Cm > 0) and (comp.Cm < 1e-6)) def test_protochans(self): - """TODO: verify the prototype cahnnel.""" + """TODO: verify the prototype channel.""" for chan_id in moose.wildcardFind('/library/##[ISA=HHChannel]'): print(moose.element(chan_id)) diff --git a/python/moose/neuroml2/test_reader2.py b/python/moose/neuroml2/test_reader2.py index 35a123f3c0..243b9dfd30 100644 --- a/python/moose/neuroml2/test_reader2.py +++ b/python/moose/neuroml2/test_reader2.py @@ -47,31 +47,31 @@ import moose from reader import NML2Reader import neuroml as nml +import os class TestPassiveCell(unittest.TestCase): def setUp(self): + if '/library' in moose.le(): + moose.delete('/library') self.reader = NML2Reader(verbose=True) - self.lib = moose.Neutral('/library') - self.filename = 'test_files/passiveCell.nml' - print('Loading: %s'%self.filename) + self.filename = os.path.realpath('test_files/passiveCell.nml') self.reader.read(self.filename) - for ncell in self.reader.nml_to_moose: - if isinstance(ncell, nml.Cell): - self.ncell = ncell + for ncell in self.reader.nml_cells_to_moose: + #if isinstance((self.reader.nml_cells_to_moose[ncell]).type,moose.Neuron): + if self.reader.nml_cells_to_moose[ncell].isA("Neuron"): + self.ncell = self.reader.nml_cells_to_moose[ncell] break - self.mcell = moose.element('/library/%s'%self.ncell.id) + self.mcell = moose.element('/library/%s'%self.ncell.name) self.soma = moose.element(self.mcell.path + '/soma') - def test_basicLoading(self): - pass self.assertEqual(self.reader.filename, self.filename, 'filename was not set') self.assertIsNotNone(self.reader.doc, 'doc is None') def test_createCellPrototype(self): - self.assertIsInstance(self.mcell, moose.Neuron) - self.assertEqual(self.mcell.name, self.ncell.id) + self.assertEqual(moose.element(self.mcell).className, 'Neuron') + self.assertEqual(moose.element(self.mcell).name, self.ncell.name) def test_createMorphology(self): for comp_id in moose.wildcardFind(self.mcell.path + '/##[ISA=Compartment]'): diff --git a/python/moose/neuroml2/test_reader3.py b/python/moose/neuroml2/test_reader3.py new file mode 100644 index 0000000000..9997a183f9 --- /dev/null +++ b/python/moose/neuroml2/test_reader3.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# test_reader.py --- +# +# Filename: test_reader3.py +# Description: +# Author: Anal Kumar +# Maintainer: +# Version: +# URL: +# Keywords: +# Compatibility: +# +# + +# Commentary: +# +# +# +# + +# Change log: +# +# +# +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, Fifth +# Floor, Boston, MA 02110-1301, USA. +# +# + +# Code: + +from __future__ import print_function +import unittest +import moose +from reader import NML2Reader +import neuroml as nml +import os +import numpy as np + +''' +Manually calculated the Vm curve given the parameters in the test_files/passiveCell.nml file. Based on the curve, the follwing are tested: +first element should be almostequal to -66.6mV +Average of the last 100ms should be -54.3mV +Ra should be 21409.5 +steady state value of Vm between 0.090 to 0.100s is -0.02761+-0.0002 +Vm at 0.0533s is -0.03725 (at 1 tau time) +''' + +class TestPassiveCell(unittest.TestCase): + def setUp(self): + if '/library' in moose.le(): + moose.delete('/library') + self.reader = NML2Reader(verbose=True) + self.lib = moose.Neutral('/library') + self.filename = os.path.realpath('test_files/passiveCell.nml') + self.reader.read(self.filename) + self.mcell = moose.element('/library/pop0/0') + self.soma = moose.element(self.mcell.path + '/soma') + if not moose.exists('vmtab'): + self.vmtab = moose.Table('vmtab') + moose.connect(self.vmtab, 'requestOut', self.soma, 'getVm') + moose.reinit() + moose.start(300e-3) + self.t = np.linspace(0, 300e-3, len(self.vmtab.vector)) + + def test_currentinj(self): + self.assertAlmostEqual(self.vmtab.vector[0], -66.6e-3, delta=0.5e-3) + self.assertAlmostEqual(np.mean(self.vmtab.vector[self.t>=200e-3]), -54.3e-3, delta=0.5e-3) + self.assertAlmostEqual(self.soma.Ra, 21409.5, delta=500) + self.assertAlmostEqual(np.mean(self.vmtab.vector[(self.t>=90e-3) & (self.t<100e-3)]), -0.0276, delta=0.5e-3) + self.assertAlmostEqual(self.vmtab.vector[np.argmin(np.abs(self.t-0.0533))], -0.03725, delta=0.5e-3) + + +if __name__ == '__main__': + unittest.main() + #p = TestPassiveCell() + +# +# test_reader.py ends here diff --git a/python/moose/neuroml2/test_reader4.py b/python/moose/neuroml2/test_reader4.py new file mode 100644 index 0000000000..99ae18f250 --- /dev/null +++ b/python/moose/neuroml2/test_reader4.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +# test_reader.py --- +# +# Filename: test_reader.py +# Description: +# Author: +# Maintainer: +# Created: Wed Jul 24 16:02:21 2013 (+0530) +# Version: +# Last-Updated: Sun Apr 17 16:13:01 2016 (-0400) +# By: subha +# Update #: 112 +# URL: +# Keywords: +# Compatibility: +# +# + +# Commentary: +# +# +# +# + +# Change log: +# +# +# +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, Fifth +# Floor, Boston, MA 02110-1301, USA. +# +# + +# Code: + +from __future__ import print_function +import unittest +import numpy as np +import moose +import neuroml as nml +from reader import NML2Reader +import os +import numpy as np +import matplotlib.pyplot as plt +from scipy.signal import find_peaks + +class TestFullCell(unittest.TestCase): + def setUp(self): + if '/library' in moose.le(): + moose.delete('/library') + self.reader = NML2Reader(verbose=True) + + self.lib = moose.Neutral('/library') + self.filename = os.path.realpath('test_files/NML2_SingleCompHHCell.nml') + self.reader.read(self.filename) + self.soma = moose.element('library/hhpop/0/soma') + + if not moose.exists('vmtab'): + self.vmtab = moose.Table('vmtab') + moose.connect(self.vmtab, 'requestOut', self.soma, 'getVm') + moose.reinit() + moose.start(300e-3) + self.t = np.linspace(0, 300e-3, len(self.vmtab.vector)) + + def test_currentinj(self): + # self.assertAlmostEqual(self.vmtab.vector[0], -66.6e-3, delta=0.5e-3) + # self.assertAlmostEqual(np.mean(self.vmtab.vector[self.t>=200e-3]), -54.3e-3, delta=0.5e-3) + # self.assertAlmostEqual(self.soma.Ra, 21409.5, delta=500) + # self.assertAlmostEqual(np.mean(self.vmtab.vector[(self.t>=90e-3) & (self.t<100e-3)]), -0.0276, delta=0.5e-3) + # self.assertAlmostEqual(self.vmtab.vector[np.argmin(np.abs(self.t-0.0533))], -0.03725, delta=0.5e-3) + peaks, peaks_dict = find_peaks(self.vmtab.vector, height=0) + act_peaks = [0.1024, 0.1186, 0.1346, 0.1507, 0.1667, 0.1827, 0.1987] + act_peaks_height = [0.03985157, 0.03131845, 0.03058362, 0.0305823 , 0.03078506, 0.03095396, 0.03086463] + self.assertEqual(len(peaks), len(act_peaks)) + for i in range(len(act_peaks)): + self.assertAlmostEqual(self.t[peaks][i], act_peaks[i], delta=1e-3) + self.assertAlmostEqual(self.vmtab.vector[peaks][i], act_peaks_height[i], delta=5e-3) + +if __name__ == '__main__': + unittest.main() + +# +# test_reader.py ends here diff --git a/setup.py b/setup.py index e4c9babd85..7c137d0e54 100644 --- a/setup.py +++ b/setup.py @@ -3,8 +3,8 @@ # module. # # Alternatively, you can use cmake build system which provides finer control -# over the build. This script is called by cmake to install the python module. -# +# over the build. This script is called by cmake to install the python module. +# # This script is compatible with python2.7 and python3+. Therefore use of # super() is commented out. # @@ -86,7 +86,7 @@ class build_ext(_build_ext): user_options = [ ('with-boost', None, 'Use Boost Libraries (OFF)') , ('with-gsl', None, 'Use Gnu Scienfific Library (ON)') - , ('with-gsl-static', None, 'Use GNU Scientific Library (static library) (OFF)') + , ('with-gsl-static', None, 'Use GNU Scientific Library (static library) (OFF)') , ('debug', None, 'Build moose in debugging mode (OFF)') , ('no-build', None, 'DO NOT BUILD. (for debugging/development)') ] + _build_ext.user_options @@ -137,8 +137,8 @@ def build_cmake(self, ext): cmake_args.append('-D%s=%s' % (k,v)) os.chdir(str(builddir_)) self.spawn(['cmake', str(sdir_)] + cmake_args) - if not self.dry_run: - self.spawn(['make', '-j%d'%numCores_]) + if not self.dry_run: + self.spawn(['make', '-j%d'%numCores_]) os.chdir(str(sdir_)) with open(os.path.join(sdir_, "README.md")) as f: