Page 1 of 1

Filter Mechanism params by NMODL PARAMETER

Posted: Thu Sep 19, 2019 7:25 am
by vogdb
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?

Re: Filter Mechanism params by NMODL PARAMETER

Posted: Thu Sep 19, 2019 10:27 am
by ted
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.

Re: Filter Mechanism params by NMODL PARAMETER

Posted: Thu Sep 19, 2019 12:27 pm
by vogdb
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)

Re: Filter Mechanism params by NMODL PARAMETER

Posted: Thu Sep 19, 2019 1:41 pm
by ramcdougal
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.

Re: Filter Mechanism params by NMODL PARAMETER

Posted: Thu Sep 19, 2019 2:24 pm
by vogdb
That is brilliant! Thank you!

Re: Filter Mechanism params by NMODL PARAMETER

Posted: Fri Sep 20, 2019 10:39 am
by ted
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.

Re: Filter Mechanism params by NMODL PARAMETER

Posted: Fri Sep 20, 2019 1:47 pm
by hines
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

Re: Filter Mechanism params by NMODL PARAMETER

Posted: Fri Sep 20, 2019 3:22 pm
by vogdb
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.

Re: Filter Mechanism params by NMODL PARAMETER

Posted: Sat Sep 21, 2019 10:02 am
by vogdb
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]