Page 1 of 1

Segfault + question

Posted: Mon May 10, 2010 4:31 pm
by breynaert
Hi everbody,

I am just learning about NEURON so please bear with me.

I am looking for a way to keep references to segments and made the following observation,
which might be helpful to other Python programmers, as NEURON behaves different from
usual Python modules:

Code: Select all

soma = Section()
segments = soma.allseg()
But you store in segments a reference to the section, not a list of segments.

As I am very stubborn, I then tried

Code: Select all

segments = [seg for seg in soma.allseg()]
Apparently, what you get is not a list with all the segments of the section but a list of references
to the same segment. This is probably because of the hoc concept of <currently accessed object>.
This time I tought I could trick Python + NEURON so typed:

Code: Select all

segments = soma.allseg
So later I could access segments()

but this failed, revealing that allseg returns a reference to the section itself, which is in turn iterable,
but not subscriptable. I think it would be useful to be able to access the segments at will without having
to calculate the x value for it, so I came up with this final statement:

Code: Select all

from copy import copy
segments = [copy(seg) for seg in soma.allseg()]

But trying to use the segments results in a segfault, which, as far as I understand is never desired.

Here is a sample code which will segfault on Python 2.6.5 and NEURON 7.1

Code: Select all

from neuron import *
from nrn import *
from copy import copy

soma = Section()
segments = [copy(seg) for seg in soma.allseg()]
vectors = []

for seg in segments:
   vector = h.Vector()
I hope this is useful, and maybe you can suggest a way to store the segments? I think it would increase
the Pythonic feel of the bindings.



Re: Segfault + question

Posted: Tue May 11, 2010 7:06 am
by hines
You're right about the segment iterators over a Section reusing the same segment object.
That seemed to be reasonable when I made the choice between a new segment object
or reuse but your discussion is close to tipping the scale toward changing it so each
seg in the iterator is a separate segment instance. When I started the NEURON+Python
interface I regretted the need to have the Segment object at all, and was thinking in terms
of a short term volatile door into the properties of Segment(x).

An idiom for what you are trying to do is

Code: Select all

from neuron import h
soma = h.Section()    
soma.nseg = 3

segments = []      
for seg in soma:

for seg in segments:
  print seg, seg.x

Do you think the above idiom solves the problem or is it still worthwhile for greater pythonicity
to change the iterator to produce distinct segment objects on each iterate. Obviously that means
some greater overhead.

The segments in the above list do not segfault when used. I'll have to look into why the copy
does not work.

Re: Segfault + question

Posted: Tue May 11, 2010 7:16 am
by hines
Sorry for the typo 'Segment(x)'. Should have been Section(x).

It would be possible to make the Section indexable so that Section returns the
ith segment. However the indexing scheme requires a design choice since most of the time one
wants the non-zero area segments (for seg in soma:) and only occasionally wants the zero area nodes
as well (at x=0 and x=1) (for seg in soma.allseg()).

Re: Segfault + question

Posted: Wed May 12, 2010 12:48 pm
by breynaert
I think the code you posted pretty much solves the problem. Probably for
design purposes, performance should be a priority, but I'm not sure on which
path would lead to better performance: either storing the x values, storing references to
the segments, or maybe coding the the allseg() function as an iterable, subscriptable object which
when iterated over, does what it currently does, but when subscripted calculates the x corresponding
to the segment and returns it. (But that would be somewhat redundant, as section(x) already does that,
so I think your idea of making the section subscriptable would be a good one, and just get rid of allseg())
On the design choice, probably it is better to include the 0 area nodes, because one could always refer to Section[1:-1].

What I found puzzling is that the reference is overwritten, so maybe a warning on that matter should be made.
So to round up, as Python programmers are not usually aware of this hoc pointer, and NEURON + Python is intended
to finally provide a native implementation fo NEURON, maybe (because code disambiguity is at the base of Python principles)
a new object should be returned for each Segment reference, but for those who care on performance (or memory footprint),
the mechanism of storing the x is still available. I'm sorry, I am not familiar enough with Python internal workings to give
good advice on whether there is a performance gain using one approach or the other, I thought that references used the
same memory, independent of the size of the object they are refering to. (What i mean with this is, that storing references
to x values or to segments would maybe have the same memory footprint?)

Thanks for the quick response, and please excuse my unclear writting, English is not my first language.


Re: Segfault + question

Posted: Fri May 14, 2010 8:47 am
by hines
I've been thinking a bit more about this and still haven't come to a clear conclusion.
I might check the performance difference but I no longer believe that is the important issue.
As I alluded to above, the original purpose of nrn.Segment was as an accessor object for
Section(x) which should only be used locally or transiently since its validity depends on
nseg and it tends to corrupt the central idea behind NEURON which is to think of nrn.Section
as much as possible as a continuous length of unbranched cable or at least with properties
which are independent of the sadly necessary underlying compartmentalization. ie. one can
change nseg at any time and the properties of the cable do not change. That idea
succeeds when properties are constant over a section but does not completely succeed when
properties are inhomogeneous since the most NEURON can do is interpolate between old and
new segment centers (pt3d info exists in the Section structure and so the best values for
area, diam, and ri always exist in each segment). So for inhomogeneities, when nseg changes,
it is best t re-execute
for seg in section: = f(seg.x)
especially if nseg significantly increases.

I guess the bottom line so far is that I don't want to give a lot of encouragement to
maintain compartment lists. But at least it is not impossible to do so with the
list.append(section(seg.x)) idiom.

It is at least clear that I need to make this a prominent part of the documentation about
nrn.Segment and the nrn.Section iterators.

From a 3-d reconstructed cell perspective, the 0<=x<=1 section location is not as useful as in the context of stylized neurons.
This is because the typical need is to iterate over a SectionList with some user defined position metric. ie.
for sec in sectionlist:
for seg in sec: = f(seg.metric.x)
where the metric is some function of the 3-d points and arc length from root.
Presently this can be done with a mod file (The CellBuild tool also supports it with
considerable generality) but it is important enough that it should be
be built-in.