possible section syntax

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

Moderator: hines

Post Reply
hines
Site Admin
Posts: 1682
Joined: Wed May 18, 2005 3:32 pm

possible section syntax

Post by hines »

I'd like to hear people's comments about the following. The hierarchy is
section, segment, mechanism, rangevariable.

Code: Select all

[hines@NeuronDev nrnpy]$ cat demo.py
from section import *

soma = Section()
print soma
soma.insert(hh)
for seg in soma :
    print seg
    for m in seg :
        print m
        for rv in m :
            print rv

soma.nseg = 5
soma.insert(hh)
for seg in soma :
        seg.diam = 2 + 3*seg.x
        seg.hh.gnabar = seg.diam * 2

for x in [.1, .5, .9] :
    print x, soma(x).x, soma(x).diam, soma(x).hh.gnabar

produces the following output:

Code: Select all

[hines@NeuronDev nrnpy]$ python demo.py
hello
create Section
<section.Section instance at 0xb7cc8c6c>
<section.Segment instance at 0xb7cc8eac>
<section.hh instance at 0xb7cc8f0c>
('gnabar', 0.12)
('gkbar', 0.035999999999999997)
0.1 0.1 2.3 4.6
0.5 0.5 3.5 7.0
0.9 0.9 4.7 9.4
[hines@NeuronDev nrnpy]$      
The section.py sample implementation is:

Code: Select all

[hines@NeuronDev nrnpy]$ cat section.py
class Section :
    def __init__(self) :
        self.change_nseg(1)
        self.L = 100
        print "create Section"
    def __iter__(self) :
        for x in self.segments :
            yield x
    def __call__(self, x) :
        i = int(x*self.nseg - .5)
        return self.segments[i]
    def __setattr__(self, attr, value) :
        if attr == 'nseg' :
            self.change_nseg(value)
        else :
            self.__dict__[attr] = value
    def change_nseg(self, value) :
        s = []
        self.__dict__['segments'] = s
        self.__dict__['nseg'] = value
        for i in range(value) :
            x = (i+.5)/value
            s.append(Segment(x))
    def insert(self, mechtype) :
        for s in self.segments :
            s.insert(mechtype)

class Segment :
    def __init__(self, pos) :
        self.x = pos
        self.v = -65.
        self.diam = 10.
        self.c = 1.
        self.mechs = {}
    def __iter__(self) :
        for x in self.mechs :
            yield self.mechs[x]
    def insert(self, mechtype) :
        m = mechtype()
        self.mechs[m.name] = m
    def __getattr__(self, attr) :
        if attr in self.mechs :
            return self.mechs[attr]
        else :
            raise AttributeError, attr

class Mechanism :
    def __init__(self) :
        self.rvs = {}
    def __iter__(self) :
        for x in self.rvs :
            yield (x, self.rvs[x])

class hh(Mechanism) :
    name = 'hh'
    def __init__(self) :
        self.rvs = {'gnabar':0.12, 'gkbar':0.036}
    def __setattr__(self, attr, value) :
        if (attr == 'rvs') :
            self.__dict__[attr] = value
        elif attr in self.__dict__['rvs'] :
            self.__dict__['rvs'][attr] = value
        else :
            raise AttributeError, attr + ' not allowed'
    def __getattr__(self, attr) :
        if attr in self.rvs :
            return self.rvs[attr]
        else :
            raise AttributeError, attr

print "hello"


[hines@NeuronDev nrnpy]$       
apdavison
Posts: 14
Joined: Tue May 24, 2005 3:56 am
Location: CNRS, Gif sur Yvette, France
Contact:

Assigning to multiple segments at once

Post by apdavison »

I like the syntax very much. It actually seems to make more sense than the equivalent hoc syntax, since "x" relates to the section and not to the mechanism variable and so is closer to the object it relates to.

What I would not like to see lost is the ability to assign the same value to all segments of a section at once, e.g.,

Code: Select all

soma.diam = 2
soma.hh.gnabar = 0.12
should have the same effect as

Code: Select all

for seg in soma:
    seg.diam = 2
    seg.hh.gnabar = 0.12
Which I guess could easily be done by extending __setattr__()

Going a bit further, it might also be nice to be able to do:

Code: Select all

dlist = (0.1,0.2,0.3,0.4,0.2)
soma.diam = dlist
which would be equivalent to:

Code: Select all

for i in range(soma.nseg):
    soma.segments[i].diam = dlist[i]
ted
Site Admin
Posts: 6289
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Assigning to multiple segments at once

Post by ted »

apdavison wrote:Going a bit further, it might also be nice to be able to do:

Code: Select all

dlist = (0.1,0.2,0.3,0.4,0.2)
soma.diam = dlist
which would be equivalent to:

Code: Select all

for i in range(soma.nseg):
    soma.segments[i].diam = dlist[i]
Would this syntax produce the following relationship between nseg and the
variation of diam along the length of a section?

Code: Select all

nseg  range  diam
====  =====  ====
1      0.5    0.1

3      1/6    0.1
       0.5    0.2
       5/6    0.3

5      0.1    0.1
       0.3    0.2
       0.5    0.3
       0.7    0.4
       0.9    0.2
apdavison
Posts: 14
Joined: Tue May 24, 2005 3:56 am
Location: CNRS, Gif sur Yvette, France
Contact:

Re: Assigning to multiple segments at once

Post by apdavison »

My original idea was that it would raise an Exception if the size of the tuple or list did not match the number of segments. If you would prefer it to fail gracefully, then either the relationship you suggest or some sort of interpolation would be possible.

Alternatively, nseg could be automatically changed to the length of the list. This seems quite elegant, although I think it's always dangerous to have secondary effects that people might not be aware of.
Raj
Posts: 220
Joined: Thu Jun 09, 2005 1:09 pm
Location: Groningen, The Netherlands
Contact:

Post by Raj »

Because of the impact changing nseg has on positions of pointprocesses I would support throwing an exception. The exception might also contain information about the dangers of changing nseg. Furthermore, (scientific) coding benefits from making variable changes explicit both in readibility/maintainability and in correctness.

Because of the side effects changing nseg has one might even consider making nseg immutable. That has the drawback that it is at odds with the interactive style of exploring the numerical model requirements that is used by many.
Last edited by Raj on Sun Apr 30, 2006 5:24 pm, edited 1 time in total.
Raj
Posts: 220
Joined: Thu Jun 09, 2005 1:09 pm
Location: Groningen, The Netherlands
Contact:

Post by Raj »

Looking back at my previous post, I realize that it is not completely clear to me when the model information is transferred from python to neuron. What is the intention, making neuron follow python instantaneously or only transferring the model information just before running the simulation?
hines
Site Admin
Posts: 1682
Joined: Wed May 18, 2005 3:32 pm

Post by hines »

The intention is that Python be a native alternative to HOC. I've gotten quite far now on the section and segment interface and most of the idioms I've learned just get repeated now over and over. As soon as the mod file interface has become automatic I'll start asking for help on the tedious process of making all the normal functions, classes, and class methods available from Python.
eacheon
Posts: 97
Joined: Wed Jan 18, 2006 2:20 pm

Post by eacheon »

This is very nice. I like the way you can do "for seg in section:"

As Dr. hines pointed out in the other thread, still the following expression is absent:

Code: Select all

s[0:1].hh.gnabar = f(0:1)
but can be done as:

Code: Select all

for seg in section:
    seg.hh.gnabar = f(seg.x)
Which is acceptable.
But __getslice__ and __setslice__ should also be implemented so we can do:

Code: Select all

for seg in section[0:0.7]:
    seg.hh.gnabar = f(seg.x)
The only flaw is, now a mechanism is associated with a segment tighter than a section, so although a mechanism is inserted into a section there's not too many operations (yet) can be done without access the underlying segments, also illustrated in apdavison's examples.

Not sure if it is easy for most NEURON users to change their mind and think this way. But hopefull this can be compensated by give more methods in Section class.

I would definitely be happy to be able to access distribute mechanisms via section, for example

Code: Select all

section.hh.constraint('gnabar', locations, f, *args)
or a fancier:

Code: Select all

locations = section.getlocations([0,0.7])
section.hh.constraint('gnabar', locations, f, *args)
or a fancier:

Code: Select all

locations = section.getlocations([0,0.7])
section.hh.gnabar[locations] = f(locations)
or
section.hh.gnabar[locations] = map(f, locations)
or even more hoc-like:

Code: Select all

section[0:1].hh.gnabar = f()[0:1]
PhilippRautenberg
Posts: 15
Joined: Wed Dec 06, 2006 10:53 am

Re: possible section syntax

Post by PhilippRautenberg »

Hi everybody,

for some of my applications it would be handy to have a list of segments (also accross sections). To create a list like this doesn't work:

Code: Select all

import neuron
soma = neuron.h.Section()
soma.nseg = 10

segmentlist = []
for seg in soma:
  segmentlist.append(seg)

for seg in segmentlist:
  print(seg.x)

# 0.95
# 0.95
# 0.95
# ...
Any suggestions?

Cheers, Philipp
apdavison
Posts: 14
Joined: Tue May 24, 2005 3:56 am
Location: CNRS, Gif sur Yvette, France
Contact:

Re: possible section syntax

Post by apdavison »

Here is one way to do what you want:

Code: Select all

import neuron
soma = neuron.h.Section()
soma.nseg = 10

first_segments = []
first_segments.append(soma.__iter__())

def list_segments(seg):
    while True:
        yield seg.next()

for first_seg in first_segments:
    for seg in list_segments(first_seg):
        print seg.x

wvangeit
Posts: 21
Joined: Wed Jun 11, 2008 2:14 am

Re: possible section syntax

Post by wvangeit »

I have one comment about this,
I've been using statements like

Code: Select all

soma = neuron.h.Section()
It's a short way of writing this down, but it's only a pity that in the hoc world this translates into an object with a strange name containing the pointer address of the object.
Since I'm still mixing sometimes some hoc code in my python model (like when I'm overriding continuerun), it's a bit difficult to get access to the right object.
Wouldn't there be a possibility to specify the hoc name of the variable when it is created like:

Code: Select all

soma = Section("soma")
I know, there is a way around it, I've created a function myself:

Code: Select all

def createSection(name):
  h('create ' + name)
  return eval("h."+name)
but I think it would be a nice addition to the 'Section' function

Werner Van Geit
Post Reply