## Recording changes in Impedance in NEURON (Python)

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

Moderator: hines

gary
Posts: 6
Joined: Wed Jan 23, 2013 5:19 pm

### Recording changes in Impedance in NEURON (Python)

Hello, I'm using the Python version of NEURON in attempt to model the transfer/input impedance at one location with respect to conductance changes at another at different instances during the course of a synaptic event. I've a simplified soma + 2 dendritic sections (i.e. o--) illustrated below:

Code: Select all

from neuron import *
from nrn import *
from pylab import *; ion();

tstop = 100 # ms

soma = Section()
soma.diam, soma.L, soma.Ra, soma.cm, soma.nseg =  10, 10, 100, 1, 1
soma.insert('pas')
soma.g_pas, soma.e_pas = 0.000222, -70

dend = [Section() for i in range(2)]

for i in range(2):
dend[i].diam, dend[i].L, dend[i].Ra, dend[i].cm, dend[i].nseg = 1, 100, 100, 1, 10
dend[i].insert('pas')
dend[i].g_pas, dend[i].e_pas = 0.000222,  -70
if not(i):
dend[i].connect(soma)
else:
dend[i].connect(dend[i-1])

eop = dend[0]                      # excitatory post-synaptic target
eip = Section(); eip.insert('hh')  # excitatory input with a spike evoked in i.c.
eipic0 = h.IClamp(0.5, sec = eip); eipic0.amp, eipic0.delay, eipic0.dur = -5, 0, 0.5*tstop
eipic1 = h.IClamp(0.5, sec = eip); eipic1.amp, eipic1.delay, eipic1.dur = 5, 0.5*tstop, 3.
edc = h.Exp2Syn(0.5, sec = eop)    # dynamic clamp of g_syn
eip.push()
enc = h.NetCon(eip(0.5)._ref_v, edc)
h.pop_section()
enc.weight[0] = 0.001              # g_max = 0.001 us
edc.tau1, edc.tau2, edc.e = 0.2, 1., 0

imp = h.Impedance()
imp.loc(0.5, sec = dend[0])
imp.transfer(0.5, sec = dend[1])

vec = {}                           # initialise dictionary
for var in 't', 'v_soma', 'i_vc', 'g_edc', 'i_edc', 'v_edc', 'z':
vec[var] = h.Vector()

vec['t'].record(h._ref_t)
vec['v_soma'].record(soma(0.5)._ref_v)
vec['g_edc'].record(edc._ref_g)
vec['i_edc'].record(edc._ref_i)
vec['v_edc'].record(eop(0.5)._ref_v)
#vec['z'].record(imp.transfer)

h.tstop = tstop; h.v_init = -70
h.init();        h.run()

t = array(vec['t'])
v = array(vec['v_soma'])
gedc = array(vec['g_edc'])
iedc = array(vec['i_edc'])
vedc = array(vec['v_edc'])
eedc = vedc - edc.e

figure()
subplot(2, 2, 1)
plot(t, v)
xlabel(r'$t$ / ms'); ylabel(r'$V$ / mV')
title('Voltage at soma')
subplot(2, 2, 2)
plot(t, gedc)
xlabel(r'$t$ / ms'); ylabel(r'$g$ / $\mu$S')
title('Conductance at dend[0]')
subplot(2, 2, 3)
plot(t, iedc)
xlabel(r'$t$ / ms'); ylabel(r'$I$ / nA')
title('Current passage at dend[0]')
subplot(2, 2, 4)
plot(t, eedc)
xlabel(r'$t$ / ms'); ylabel(r'$\Delta V$ / mV')
title('E.M.F. at dend[0]')
#waitforbuttonpress()

Using the instantiation of the Impedance class (imp) I can see how use the member functions imp.input() and imp.transfer() to return single values. However is there a way to record' the changes in impedance over time in a manner that is similar to the convenient syntax for the other variables (e.g. vec['g_edc'].record(edc._ref_g) )?

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

### Re: Recording changes in Impedance in NEURON (Python)

No. To quote the Programmer's Reference entry on the Vector class's record() method, "[data] Transfers [to the Vector] take place on exit from finitialize() and on exit from fadvance()." Any variable whose value is not automatically updated by finitialize() and fadvance() will simply be recorded as a stream of identical values, equal to whatever it was before run() is executed. Impedance is calculated only when Impedance class's compute() method is called, and the run control system doesn't do that for you.

That said, you can customize NEURON's standard run system by loading the following AFTER load_file("nrngui.hoc") and all statements that set up your model have been executed:

Code: Select all

objref zvec
zvec = new Vector()

getnewz() {
. . . statements that calculate the desired impedance value
at the current time, and append it to zvec . . .
}

proc initzvec() {
zvec.resize(0)
getnewz()
}

objref fih
fih = new FInitializeHandler("initzvec()")

getnewz()
}
The FInitializeHandler executes initzvec() at the end of model initialization.
initzvec discards any old data that may have been contained in zvec, and records the desired impedance at t=0.
proc advance(), which replaces the standard run system's built-in advance(), makes sure that a new impedance value is calculated after each time step, and appends it to zvec.

You'll want to read the Programmer's Reference about the FInitializeHandler class, and you should also read about model initialization and the standard run system (chapters 7 and 8 of the NEURON Book).

A BIG CAVEAT:

Impedance is a frequency-domain concept that only makes sense in the context of a stationary or pseudostationary linear system. This means that
(1) peak to peak signal amplitude (voltage or current) must lie within a range narrow enough that the system is approximately linear
AND
(2) the system whose impedance is being measured or calculated is quasistationary at the frequencies of interest. This means it isn't changing, or if changes are occurring, they happen on a time scale that is slow compared to the frequencies of interest. In other words, during a synaptic conductance change that has a half width of T seconds, it doesn't make sense to talk about DC input resistance or input impedance at frequencies (in Hz) much lower than about 0.35/T (the 0.35 is from the relationship
BW = 0.35/risetime
where risetime is the 10-90 rise time of a first order low pass filter, and BW is that filter's bandwidth in Hz).

Example: given an inhibitory conductance with decay time constant tau, the half width of the conductance change is about tau*ln(2). If tau is 20 ms, the half width is ~ 14 ms, which corresponds to 25 Hz.

gary
Posts: 6
Joined: Wed Jan 23, 2013 5:19 pm

### Re: Recording changes in Impedance in NEURON (Python)

Thanks Ted for a swift, clear, and comprehensive response. With regards to the caveats, it is reassuring to know that our assumptions of linearity and stationarity are supported by small changes in V/I amplitude with frequencies of interest that are certainly greater than the those associated with the synaptic conductance time constants. But thank you very much for a detailed description of how the assumptions can be tested properly.

I will look into modifying the run system in attempt to implement the suggestion you have made. My present NEURON code is written in Python because I am much more familiar with Python than hoc. I imagine it would not be tractable to introduce the customisations you have suggested in Python but I would be delighted to be proved otherwise! In the meantime, however, I will first read the recommended Chapters in The Neuron Book and I am optimistic that this will guide my way.

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

### Re: Recording changes in Impedance in NEURON (Python)

The standard run system is written in hoc.
makes it available.
h.run() calls its run() procedure to launch a simulation.

To replace any of the standard run system's procedures or functions, it is easiest to create a text file that contains the hoc statements that define the proc or func the way you want it, then insert a h.load_file() statement in your Python program so that NEURON will read that hoc file's contents.

gary
Posts: 6
Joined: Wed Jan 23, 2013 5:19 pm

### Re: Recording changes in Impedance in NEURON (Python)

Thanks again for your helpful suggestions, which I am presently trying to implement!

I'm hoping to investigate the effects of conductance changes, occurring at a handful of synchronous synaptic inputs onto dendrites of a cell with an input resistance of ~20 Mohm and capacitance ~300 pF, on the input resistances at all locations throughout the dendritic tree (using conductance rise & decay constants 0.2ms & 2ms). I can see how to use the Impedance class to determine the change in input resistance at any desired location arising from conductance introduced from one location. I cannot see however how to evaluate the resultant change in input resistance arising from more than one location of conductance perturbation. Is it valid to instantiate as many Impedance class objects as there are inputs and sum the Ztransfer or Zinput values computed from each object linearly or is there a better way?

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

### Re: Recording changes in Impedance in NEURON (Python)

Is it valid to instantiate as many Impedance class objects as there are inputs and sum the Ztransfer or Zinput values computed from each object linearly
That would violate the very concepts of transfer and input impedance.
gary wrote:I'm hoping to investigate the effects of conductance changes, occurring at a handful of synchronous synaptic inputs onto dendrites of a cell with an input resistance of ~20 Mohm and capacitance ~300 pF, on the input resistances at all locations throughout the dendritic tree
If the perturbations are simultaneous, just activate all of them and then calculate whatever input impedances you need.

If your model has voltage-gated channels, be sure to execute compute with the 2nd argument == 1 so that it performs the extended impedance calculation, which includes the effect of membrane potential fluctuations on gating states.

gary
Posts: 6
Joined: Wed Jan 23, 2013 5:19 pm

### Re: Recording changes in Impedance in NEURON (Python)

ted wrote:If the perturbations are simultaneous, just activate all of them and then calculate whatever input impedances you need.
If your model has voltage-gated channels, be sure to execute compute with the 2nd argument == 1 so that it performs the extended impedance calculation, which includes the effect of membrane potential fluctuations on gating states.
Thanks Ted, you're description of what to do is incredibly helpful; I was making a simple problem unnecessarily complex (not to mention just plain wrong). I was confused by having to use the Impedance.loc() member function to prevent Impedance.compute() function from returning the error Impedance stimulus location is not specified' when all I really wanted was the input impedance at the currently access section. By entering an arbitrary location in loc() (which I can see now is only relevant for Ztransfer), Impedance.compute() can return Zinput (independent of the input argument for loc()) values using Impedance.input() e.g.

Code: Select all

...
h.v_init = -70
h.init()

imp = h.Impedance()
imp.loc(0.5, soma)

nstep = int(h.tstop / h.dt)
ip = numpy.empty(nstep, dtype = float) # storage array to record changes in input impedance

for i in range(nstep):
h.step()
dend[0].push()
imp.compute(0, 1)
h.pop_section()
ip[i] = imp.input(0.5)


figoyouwei
Posts: 41
Joined: Sun Aug 08, 2010 11:09 am

### Re: Recording changes in Impedance in NEURON (Python)

Dear Ted,

Is that possible for record impedance with the Vector.record function in the hoc ?

for example, something similar syntax like that to avoid putting it in a loop ?
vec.record(&soma, imp.input(0.5))

Thank you

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

### Re: Recording changes in Impedance in NEURON (Python)

Vector.record only captures the value of a scalar variable. The Impedance class's methods are functions, not variables. If you want to know the impedance at a particular point at a particular time, it is necessary to call that function at that time. If you want to capture the time course of impedance to a Vector, then at each time step you must force calculation of the new value of the impedance and append it to a Vector yourself, as described in my earlier posts on this thread.

Example: suppose your model has a section called soma, and you want to capture the time course of input impedance at the middle of the soma. You'll want to customize the hoc code

Code: Select all

objref zvec
zvec = new Vector()
. . .
from my previous example by adding these statements

Code: Select all

FREQ = 10 // Hz, just an example value
objref imp
imp = new Impedance()
objref tvec
tvec = new Vector()
tvec.record(&t)
immediately after the zvec = new Vector() statement,
and change getnewz() to

Code: Select all

getnewz() {
imp.compute(FREQ)
soma zvec.append(imp.input(0.5))
}

figoyouwei
Posts: 41
Joined: Sun Aug 08, 2010 11:09 am

### Re: Recording changes in Impedance in NEURON (Python)

Dear Ted,

The impedance example works, thank you. Though it brought up another issue which I didn't run into because I always used to simulate with run() command.

In hoc, after setting up a Vector.
objref vec
vec = new Vector()
vec.record(&soma.v(0.5))

Both run() and while (t <= tstop) { fadvance() } work !

*****
However, in Python, after setting up a Vector.
vec = h.Vector()
vec.record(getattr(h.soma(0.5), '_ref_v'), h.dt)

It works by run() but NOT while (t <= tstop) { fadvance() }

Am I missing anything here ?

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

### Re: Recording changes in Impedance in NEURON (Python)

Did you remember to call
finitialize(v_init)
before calling while (...) ?

figoyouwei
Posts: 41
Joined: Sun Aug 08, 2010 11:09 am

### Re: Recording changes in Impedance in NEURON (Python)

Dear Ted,

recording impedance using the NEURON impedance class works perfectly. Thank you !

but ... another question, how to do a shape plot of impedance throughout a model ? Like in the "Harnett and Magee 2012 Nature" Fig.3a (right) ?

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

### Re: Recording changes in Impedance in NEURON (Python)

figoyouwei wrote:how to do a shape plot of impedance throughout a model ? Like in the "Harnett and Magee 2012 Nature" Fig.3a (right) ?
Here are the steps
1. Insert a dummy mechanism that has a RANGE variable into all sections. Here's the source code for such a mechanism:

Code: Select all

NEURON {
SUFFIX var
RANGE zin
}
ASSIGNED {
zin (1)
}
2. Compute impedances at the frequency of interest. For the sake of this example, I will assume that your instance of the impedance class is called imp.
3. For each internal node of every section in your model, set x_var at that location to the value of the input impedance at that location. This is easier to say than to do.
forall for (x,0) zin_var(x) = imp.input(x)
4. Bring up a Shape plot, click on its menu box, and select Plot what? Enter
zin_var
into the symbol chooser, then click on Accept.
5. Click on the Shape plot's menu box and select the very last item, which is called "Shape Plot".

If you want a logarithmic scale like the one used by Harnett et al., then step 3's formula becomes
forall for (x,0) zin_var(x) = log(imp.input(x))
or
forall for (x,0) zin_var(x) = log10(imp.input(x))

If you want a different color scale than the default used by NEURON, go to the FAQ list
http://www.neuron.yale.edu/neuron/faq
and look for this question
How do I change the color scale used in shape plots?

figoyouwei
Posts: 41
Joined: Sun Aug 08, 2010 11:09 am

### Re: Recording changes in Impedance in NEURON (Python)

thank you Ted, it works pure :)

another small question on this topic, when we do:
-> imp.compute(frequency)

some models chose the frequency = 10, what does this frequency exactly mean under the hook ?

ted