Filter Mechanism params by NMODL PARAMETER

When Python is the interpreter, what is a good
design for the interface to the basic NEURON
concepts.

Moderator: hines

Post Reply
vogdb
Posts: 23
Joined: Sun Aug 13, 2017 9:51 am

Filter Mechanism params by NMODL PARAMETER

Post by vogdb » Thu Sep 19, 2019 7:25 am

Hello! I'm collecting all cell's mechanisms in Python like this:

Code: Select all

soma = h.Section(name='soma')
// soma.insert( lots of mechanisms )
for seg in soma:
    for mech in seg:
        print(mech)
mech contains parameters like 'gbar', 'g', 'ica' and so on. How can I filter them to get only those that are in 'PARAMETER' block of their corresponding `.mod` file?

Code: Select all

NEURON	{
        ...
	RANGE gbar, g, ica
}

PARAMETER	{
	gbar = 0.00001 (S/cm2)
}
Considering this example I would like to get `gbar` but leave out `g`. Would it be possible to do?

ted
Site Admin
Posts: 5590
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Filter Mechanism params by NMODL PARAMETER

Post by ted » Thu Sep 19, 2019 10:27 am

mech contains parameters like 'gbar', 'g', 'ica' and so on.
Not what I see. Given

Code: Select all

soma = h.Section(name='soma')
soma.insert('hh')
then

Code: Select all

for seg in soma:
  for mech in seg:
    print(mech)
returns

Code: Select all

k_ion
na_ion
hh
but no mention of gnabar, gkbar, gl. or el, which are declared in hh.mod's PARAMETER block.

vogdb
Posts: 23
Joined: Sun Aug 13, 2017 9:51 am

Re: Filter Mechanism params by NMODL PARAMETER

Post by vogdb » Thu Sep 19, 2019 12:27 pm

If to be that precise, lets take this example:

Code: Select all

soma = h.Section(name='soma')
soma.insert('hh')

for seg in soma:
    for mech in seg:
        if mech.name() == 'hh':
            filtered = []
            for n in dir(mech):
                v = getattr(mech, n)
                if n.startswith('__') or n in ('next', 'name', 'is_ion', 'segment',):
                    continue
                filtered.append(n)
            print(filtered)
            # ['el', 'gk', 'gkbar', 'gl', 'gna', 'gnabar', 'h', 'il', 'm', 'n']
How can I make `filtered` to contain `['el', 'gkbar', 'gl', 'gnabar']` that are in `PARAMETER` block of `hh.mod`?

Code: Select all

PARAMETER {
        gnabar = .12 (S/cm2)	<0,1e9>
        gkbar = .036 (S/cm2)	<0,1e9>
        gl = .0003 (S/cm2)	<0,1e9>
        el = -54.3 (mV)

ramcdougal
Posts: 154
Joined: Fri Nov 28, 2008 3:38 pm
Location: Yale School of Medicine

Re: Filter Mechanism params by NMODL PARAMETER

Post by ramcdougal » Thu Sep 19, 2019 1:41 pm

As long as you're using NEURON 7.7+, mod file code is available for introspection from Python, so it can be parsed manually with a handful of lines of Python. Here's a function that seems to work to get parameters:

Code: Select all

from neuron import h
import re

def get_parameters(mech_name):
    mech = h.MechanismType(0)
    mech.select(mech_name)
    parameters = {}
    code = mech.code().split('\n')
    inside_comment = False
    inside_parameter = False
    for line in code:
        line = line.strip()
        lineupper = line.upper()
        if not line:
            continue
        if line[0] in ('?', ':'):
            continue
        if lineupper.startswith('COMMENT'):
            inside_comment = True
        elif lineupper.startswith('ENDCOMMENT'):
            if not inside_comment:
                raise('Parse error')
            inside_comment = False
        elif not inside_comment:
            if lineupper.startswith('PARAMETER'):
                inside_parameter = True
            elif lineupper.startswith('}') and inside_parameter:
                inside_parameter = False
            elif inside_parameter:
                # discard any comments
                # NB: colon can also appear as part of a CURIE in other parts of a mod file
                #     but not in the PARAMETERS block
                line = line.split(':')[0].strip()
                if not line:
                    continue
                varname, value, metadata = re.match('(\w+)\s*=\s*(-?[0-9\.]+)\s*(.*)', line).groups()
                parameters[varname] = {'value': value}
                if metadata:
                    parsed_metadata = re.match(r'(\((([\w/])+)\))?\s*(.*)', metadata).groups()
                    if parsed_metadata[1] is not None:
                        parameters[varname]['units'] = parsed_metadata[1]
                    if parsed_metadata[-1]:
                        parameters[varname]['bounds'] = parsed_metadata[-1]
    return parameters
For example, if you call it with:

Code: Select all

import pprint
pprint.pprint(get_parameters('hh'))
Then it will display:

Code: Select all

{'el': {'units': 'mV', 'value': '-54.3'},
 'gkbar': {'bounds': '<0,1e9>', 'units': 'S/cm2', 'value': '.036'},
 'gl': {'bounds': '<0,1e9>', 'units': 'S/cm2', 'value': '.0003'},
 'gnabar': {'bounds': '<0,1e9>', 'units': 'S/cm2', 'value': '.12'}}
There is also a proper Python NMODL parser available at https://bluebrain.github.io/nmodl/ that could be used to generate the same data, but the above solution works without installing any additional packages.

vogdb
Posts: 23
Joined: Sun Aug 13, 2017 9:51 am

Re: Filter Mechanism params by NMODL PARAMETER

Post by vogdb » Thu Sep 19, 2019 2:24 pm

That is brilliant! Thank you!

ted
Site Admin
Posts: 5590
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Filter Mechanism params by NMODL PARAMETER

Post by ted » Fri Sep 20, 2019 10:39 am

Brilliant up to a point. The NMODL source code will tell you the default values of parameters. However, it won't tell you the actual value of any parameter used in a particular model implementation, because those can be changed by hoc or Python assignment statements. Also, if mechanism X's PARAMETER is also a range variable, every instance of X can have a different value for that parameter.

Finally, remember that some NMODL code (mis)declares some variables to be PARAMETERs and (mistakenly) assigns values to them even though those variables will actually get their values at runtime from code outside of the NMODL file. The most obvious example is celsius, but there are others. Such variables should really be declared in the ASSIGNED block.

Bottom line: although NEURON's new ability to introspect NMODL source code from compiled mechanisms can be truly useful, you still need to be careful about interpreting code written by yourself and others.

hines
Site Admin
Posts: 1577
Joined: Wed May 18, 2005 3:32 pm

Re: Filter Mechanism params by NMODL PARAMETER

Post by hines » Fri Sep 20, 2019 1:47 pm

An old way of getting the PARAMETER names of a mechanism is

Code: Select all

from neuron import h
ms = h.MechanismStandard("hh", 1)
parm_name = h.ref("")
for i in range(ms.count()):
  ms.name(parm_name, i)
  print(parm_name[0])
https://www.neuron.yale.edu/neuron/stat ... ndard.name

vogdb
Posts: 23
Joined: Sun Aug 13, 2017 9:51 am

Re: Filter Mechanism params by NMODL PARAMETER

Post by vogdb » Fri Sep 20, 2019 3:22 pm

Thank you so much for so many options. I will try the old way tomorrow as it looks very neat. Today I've ended up with this solution:

Code: Select all

from neuron import h
from nmodl import dsl

mech_type = h.MechanismType(0)
mech_type.select('hh')
code = mech_type.code()
driver = dsl.NmodlDriver()
modast = driver.parse_string(code)
lookup_visitor = dsl.visitor.AstLookupVisitor()
param_block = lookup_visitor.lookup(modast, dsl.ast.AstNodeType.PARAM_ASSIGN)

params = {}
for param in param_block:
    name = param.name.value.value
    value = None
    if param.value is not None:
        value = param.value.value
    params[name] = value
return params
If someone would try the solution by ramcdougal then it would be better to replace

Code: Select all

varname, value, metadata = re.match('(\w+)\s*=\s*(-?[0-9\.]+)\s*(.*)', line).groups()
with

Code: Select all

varname, value, metadata = re.match(r'(\w+)\s*(?:=\s*(-?[0-9.]+)\s*)?(.*)', line).groups()
otherwise you would have problems when value is not presented.

I completely agree that this method is not reliable for values extraction. That is why I'm using it only for parameters names extraction.

vogdb
Posts: 23
Joined: Sun Aug 13, 2017 9:51 am

Re: Filter Mechanism params by NMODL PARAMETER

Post by vogdb » Sat Sep 21, 2019 10:02 am

Here is the today's solution. Thank you again!

Code: Select all

    ms = h.MechanismStandard(mech_name, 1)
    param_name = h.ref('')
    param_names = []
    for i in range(ms.count()):
        ms.name(param_name, i)
        param_names.append(param_name[0])
    param_names = [name.split('_' + mech_name)[0] for name in param_names]

Post Reply