Skip to content

Commit 8939ede

Browse files
subhacomhrani
andauthored
Updated neuroml2 imports with error messages (#472)
* Fixed showmsg() bug in pybind11 based version. The newer implementation of showmsg() shows the outgoing messages with misdirected arrows. Fixed now. * Added newer version of pybind11 * Swapped clocks for channel and compartment to fix #467 * This actually fixes scheduling for channels and compartments #467 The previous commit only updated the docs. This one modifies the actual tick assignments. Now electrical compartments are scheduled on ticks 2 and 3 and channels (all derived from ChanBase) on 4. * Minor fix for compiler warning on loop var creating copy from const * Removed CMake generated compile command. the compile command file is generated by cmake in each build environment and should not be part of the repo. * Added error message at neuroml import error, corrected imports. * Updated neuroml2 reader. Yet to debug Granule_98 model. * Updated neuroml2 reader to handle spherical compartment for CaPool Also created separate test script for Granule98 model. * Fixed deprecated imp module use in rdesigneur. - rdesigneur used imp module, now replaced by importlib. - commented out debug logs from neuroml2 reader - TODO: tests/support has files which conflict with tests/core. These seem to be old test code which may better be removed. * Updated test script for Granule98 model --------- Co-authored-by: HarshaRani <[email protected]>
1 parent 5639f3e commit 8939ede

File tree

6 files changed

+131
-49
lines changed

6 files changed

+131
-49
lines changed

python/moose/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ def doc(arg, paged=True):
740740
741741
"""
742742
text = _moose.__generatedoc__(arg)
743-
if pydoc.page:
743+
if pydoc.pager:
744744
pydoc.pager(text)
745745
else:
746746
print(text)

python/moose/neuroml2/reader.py

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,26 @@
1313

1414
import os
1515
import math
16+
import logging
1617
import numpy as np
1718
import moose
1819

19-
import logging
20+
2021
logger_ = logging.getLogger('moose.nml2')
2122

22-
import neuroml as nml
23-
import pyneuroml.pynml as pynml
23+
24+
nml_not_available_msg = ''
25+
26+
try:
27+
import neuroml as nml
28+
import pyneuroml.pynml as pynml
29+
except ImportError as error:
30+
raise ImportError(f'Could not import neuroml/pyneuroml. Please make sure you have pyneuroml installed (`pip install pyneuroml`)') from error
31+
32+
2433
from moose.neuroml2.units import SI
2534

35+
2636
def _write_flattened_nml( doc, outfile ):
2737
"""_write_flattened_nml
2838
Concat all NML2 read by moose and generate one flattened NML file.
@@ -68,14 +78,15 @@ def _unique( ls ):
6878

6979
def _isConcDep(ct):
7080
"""_isConcDep
71-
Check if componet is dependant on concentration. Most HHGates are
72-
dependant on voltage.
81+
Check if componet is dependent on concentration. Most HHGates are
82+
dependent on voltage.
7383
7484
:param ct: ComponentType
7585
:type ct: nml.ComponentType
7686
7787
:return: True if Component is depenant on conc, False otherwise.
7888
"""
89+
# logger_.debug(f"{'#' * 10} EXTENDS {ct.extends}")
7990
if 'ConcDep' in ct.extends:
8091
return True
8192
return False
@@ -209,6 +220,7 @@ def read(self, filename, symmetric=True):
209220
self.importInputs(self.doc)
210221

211222
for cell in self.doc.cells:
223+
# logger_.debug(f"{'%' * 10} Creating cell prototype {cell}")
212224
self.createCellPrototype(cell, symmetric=symmetric)
213225

214226
if len(self.doc.networks)>=1:
@@ -427,10 +439,15 @@ def copySpecies(self, species, compartment):
427439
raise RuntimeError(msg)
428440
pool_id = moose.copy(proto_pool, compartment, species.id)
429441
pool = moose.element(pool_id)
430-
pool.B = pool.B / (np.pi * compartment.length * (
442+
# print('&' * 10, compartment.path, compartment.length, compartment.diameter, pool.thick)
443+
if compartment.length <= 0:
444+
vol = 4 * np.pi * (0.5 * compartment.diameter**3 - (0.5 * compartment.diameter - pool.thick)**3) / 3
445+
else:
446+
vol = (np.pi * compartment.length * (
431447
0.5 * compartment.diameter + pool.thick) *
432448
(0.5 * compartment.diameter - pool.thick)
433449
)
450+
pool.B = pool.B / vol
434451
return pool
435452

436453
def importAxialResistance(self, nmlcell, intracellularProperties):
@@ -475,18 +492,20 @@ def calculateRateFn(self, ratefn, vmin, vmax, tablen=3000, vShift='0mV'):
475492
if ratefn.type != ct.name:
476493
continue
477494

478-
logger_.info("Using %s to evaluate rate"%ct.name)
495+
logger_.info(f"Using %s to evaluate rate"%ct.name)
479496
rate = []
480497
for v in tab:
481-
# Note: MOOSE HHGate are either voltage of concentration
482-
# dependant. Here we figure out if nml description of gate is
483-
# concentration dependant or note.
498+
# Note: MOOSE HHGate are voltage and/or concentration
499+
# dependent. Here we figure out if nml description of gate is
500+
# concentration dependent or not.
501+
# logger_.debug(f"{'#' * 5} {_isConcDep(ct)}")
484502
if _isConcDep(ct):
485-
# Concentration dependant. Concentration can't be negative.
503+
# Concentration dependent. Concentration can't be negative.
486504
# Find a suitable CaConc from the /library. Currently on Ca
487-
# dependant channels are allowed.
505+
# dependent channels are allowed.
488506
caConcName = _findCaConcVariableName()
489-
req_vars = {caConcName:'%g'%max(0,v),'vShift':vShift,'temperature':self._getTemperature()}
507+
req_vars = {'v': '0.0V', 'caConc':f'{max(1e-11,v):g}', caConcName:f'{max(1e-11,v):g}','vShift':vShift,'temperature':self._getTemperature()}
508+
# logger_.debug(f"{'A' * 30} {req_vars}")
490509
else:
491510
req_vars = {'v':'%sV'%v,'vShift':vShift,'temperature':self._getTemperature()}
492511
req_vars.update( self._variables )
@@ -669,6 +688,7 @@ def importInputs(self, doc):
669688
pg.firstWidth = SI(pg_nml.duration)
670689
pg.firstLevel = SI(pg_nml.amplitude)
671690
pg.secondDelay = 1e9
691+
logger_.debug(f'{"$" * 10} Created input {epath}')
672692

673693

674694
def importIonChannels(self, doc, vmin=-150e-3, vmax=100e-3, vdivs=5000):
@@ -707,6 +727,6 @@ def createDecayingPoolConcentrationModel(self, concModel):
707727
# shell and d is thickness - must divide by
708728
# shell volume when copying
709729
self.proto_pools[concModel.id] = ca
710-
self.nml_concs_to_moose[concModel.id] = ca
730+
self.nml_conc_to_moose[concModel.id] = ca
711731
self.moose_to_nml[ca] = concModel
712732
logger_.debug('Created moose element: %s for nml conc %s' % (ca.path, concModel.id))
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# test_granule98.py ---
2+
#
3+
# Filename: test_granule98.py
4+
# Description:
5+
# Author: Subhasis Ray
6+
# Created: Mon Apr 8 21:41:22 2024 (+0530)
7+
# Last-Updated: Wed Apr 10 19:59:48 2024 (+0530)
8+
# By: Subhasis Ray
9+
#
10+
11+
# Code:
12+
"""Test code for the Granule cell model
13+
14+
"""
15+
import os
16+
import numpy as np
17+
# import unittest
18+
import logging
19+
20+
21+
LOGLEVEL = os.environ.get('LOGLEVEL', 'INFO')
22+
logging.basicConfig(level=LOGLEVEL)
23+
24+
25+
import moose
26+
from moose.neuroml2.reader import NML2Reader
27+
28+
29+
def run(nogui=True):
30+
reader = NML2Reader()
31+
filename = 'test_files/Granule_98/GranuleCell.net.nml'
32+
reader.read(filename)
33+
soma = reader.getComp(reader.doc.networks[0].populations[0].id, 0, 0)
34+
data = moose.Neutral('/data')
35+
pg = reader.getInput('Gran_10pA')
36+
inj = moose.Table(f'{data.path}/pulse')
37+
moose.connect(inj, 'requestOut', pg, 'getOutputValue')
38+
vm = moose.Table(f'{data.path}/Vm')
39+
moose.connect(vm, 'requestOut', soma, 'getVm')
40+
print('A' * 10, soma)
41+
42+
simtime = 300e-3
43+
moose.reinit()
44+
moose.start(simtime)
45+
46+
t = np.arange(len(vm.vector)) * vm.dt
47+
print('%' * 10, len(vm.vector), len(inj.vector))
48+
results = np.array([t, vm.vector, inj.vector], dtype=[('time', float), ('Vm', float), ('Im', float)])
49+
fname = 'Granule_98.npy'
50+
np.save(fname, results)
51+
print(f'Saved results in {fname}')
52+
if not nogui:
53+
import matplotlib.pyplot as plt
54+
fig, axes = plt.subplots(nrows=2, sharex='all')
55+
axes[0].plot(t, vm.vector, label='Vm')
56+
axes[1].plot(t, inj.vector, label='Im')
57+
plt.legend()
58+
plt.show()
59+
60+
61+
run(nogui=False)
62+
63+
64+
#
65+
# test_granule98.py ends here

python/moose/neuroml2/test_reader.py

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
# Maintainer:
88
# Created: Wed Jul 24 16:02:21 2013 (+0530)
99
# Version:
10-
# Last-Updated: Sun Apr 17 16:13:01 2016 (-0400)
11-
# By: subha
12-
# Update #: 112
10+
# Last-Updated: Mon Apr 8 21:41:42 2024 (+0530)
11+
# By: Subhasis Ray
12+
# Update #: 125
1313
# URL:
1414
# Keywords:
1515
# Compatibility:
@@ -46,13 +46,18 @@
4646

4747
# Code:
4848

49-
from __future__ import print_function
49+
import os
5050
import unittest
5151
import numpy as np
52+
import logging
53+
54+
55+
LOGLEVEL = os.environ.get('LOGLEVEL', 'INFO')
56+
logging.basicConfig(level=LOGLEVEL)
57+
58+
5259
import moose
53-
import neuroml as nml
54-
from reader import NML2Reader
55-
import os
60+
from moose.neuroml2.reader import NML2Reader
5661

5762
class TestFullCell(unittest.TestCase):
5863
def setUp(self):
@@ -125,24 +130,6 @@ def test_HHChannels(self):
125130
self.assertTrue(len(chans) < 3) # Only soma and dendrite2 have the channels
126131
self.assertAlmostEqual(soma_na.Gbar, 120e-2 * self.soma.diameter * self.soma.diameter * np.pi, places=6)
127132

128-
'''
129-
Not yet working in NML2...
130-
131-
class TestGran98(unittest.TestCase):
132-
def setUp(self):
133-
self.reader = NML2Reader()
134-
self.lib = moose.Neutral('/library')
135-
self.filename = 'test_files/Granule_98/Granule_98.nml'
136-
self.reader.read(self.filename)
137-
for ncell in self.reader.nml_to_moose:
138-
if isinstance(ncell, nml.Cell):
139-
self.ncell = ncell
140-
break
141-
self.mcell = moose.element(moose.wildcardFind('/##[ISA=Cell]')[0])
142-
143-
def test_CaPool(self):
144-
pass
145-
'''
146133

147134
if __name__ == '__main__':
148135
unittest.main()

python/moose/neuroml2/test_reader2.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,19 @@
4343
# Code:
4444

4545
from __future__ import print_function
46+
47+
import os
4648
import unittest
49+
import logging
50+
51+
52+
LOGLEVEL = os.environ.get('LOGLEVEL', 'INFO')
53+
logging.basicConfig(level=LOGLEVEL)
54+
55+
4756
import moose
48-
from reader import NML2Reader
49-
import neuroml as nml
50-
import os
57+
from moose.neuroml2.reader import NML2Reader
58+
5159

5260
class TestPassiveCell(unittest.TestCase):
5361
def setUp(self):

python/rdesigneur/rdesigneur.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@
1616
## latter in the former, including mapping entities like calcium and
1717
## channel conductances, between them.
1818
##########################################################################
19-
from __future__ import print_function, absolute_import, division
2019

21-
# FIXME: Deprecated since 3.4
22-
import imp
20+
import importlib
2321
import os
2422
import moose
2523
import numpy as np
@@ -323,14 +321,18 @@ def buildProtoFromFunction( self, func, protoName ):
323321
modulePath = os.path.realpath(os.path.join(*pathTokens[:-1]))
324322
moduleName = pathTokens[-1]
325323
funcName = func[modPos+1:bracePos]
326-
moduleFile, pathName, description = imp.find_module(moduleName, [modulePath])
324+
# moduleFile, pathName, description = imp.find_module(moduleName, [modulePath])
325+
# `imp` has been deprecated and throws error in Python 3.12
326+
spec = importlib.machinery.PathFinder().find_spec(moduleName, [modulePath])
327327
try:
328-
module = imp.load_module(moduleName, moduleFile, pathName, description)
328+
# module = imp.load_module(moduleName, moduleFile, pathName, description)
329+
module = importlib.util.module_from_spec(spec)
329330
funcObj = getattr(module, funcName)
330331
funcObj(protoName)
331332
return True
332333
finally:
333-
moduleFile.close()
334+
pass
335+
# moduleFile.close()
334336
return False
335337
if not func[0:bracePos] in globals():
336338
raise BuildError( \

0 commit comments

Comments
 (0)