neuronsimulator / nrn

NEURON Simulator
http://nrn.readthedocs.io
Other
389 stars 115 forks source link

Inconsistency recording h._ref_t in successive simulations #1520

Open ec753 opened 2 years ago

ec753 commented 2 years ago

Context

Issue when running successive simulations in python: h._ref_t points to the first section created unless otherwise specified, instead of the last section created.

Overview of the issue

h._ref_t points to the first section created, causing potential issues when running successive simulations. In the example below, t2 = h.Vector().record(h._ref_t) creates a pointer to soma1 instead of soma2 (expected behavior). Thus, writing over soma1, the first section created, causes t2 to be terminated.

from neuron import h
soma1 = h.Section(name="soma1")
t1 = h.Vector().record(h._ref_t)

soma2 = h.Section(name="soma2")
t2 = h.Vector().record(h._ref_t)

soma1 = None

h.finitialize(-65)
h.fadvance()
print(list(t2))

output: []

In contrast, if soma1 is the 2nd section made instead of the first, then it being overwritten does not have an effect on t2.

from neuron import h
soma0 = h.Section(name="soma0")

soma1 = h.Section(name="soma1")
t1 = h.Vector().record(h._ref_t)

soma2 = h.Section(name="soma2")
t2 = h.Vector().record(h._ref_t)

soma1 = None

h.finitialize(-65)
h.fadvance()
print(list(t2))

output: [0.0, 0.025]

This can be easily remedied by specifying the section for which to record h._ref_t from.

from neuron import h
soma1 = h.Section(name="soma1")
t1 = h.Vector().record(h._ref_t)

soma2 = h.Section(name="soma2", sec=soma2)
t2 = h.Vector().record(h._ref_t)

soma1 = None

h.finitialize(-65)
h.fadvance()
print(list(t2))

output: [0.0, 0.025]

Expected result/behavior

Recording h._ref_t should either point to the last section created (instead of the first) or require the user to specify the section to record and pass an error if there is not one.

from neuron import h
soma1 = h.Section(name="soma1")
t1 = h.Vector().record(h._ref_t)

soma2 = h.Section(name="soma2")
t2 = h.Vector().record(h._ref_t)
soma1 = None

h.finitialize(-65)
h.fadvance()
print(list(t2))

output: [0.0, 0.025]

NEURON setup

nrnhines commented 2 years ago

vec.record(h._ref_t, sec=section) associates with some section in order to determine which local variable time step instance to record or which thread time to record. By default (without the sec= keyword arg), that happens to be the default currently accessed section. It is a sad side effect that if the section is deleted, then vec no longer records that time. Ironically, except for the local variable time step method, all threads generate the same time series so it doesn't matter which thread is used to record for the fixed step method and the global variable time step method.

I think it would be safe for me to have TVecRecord instances just turn off their Observer functionality which watches for deletion of the section they were associated with. But this would break the local variable step method if the user did not supply vec.record with the PointProcess hint as the first arg (see https://nrn.readthedocs.io/en/latest/python/programming/math/vector.html#Vector.record)