Parallel NMODL array assignment

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

Moderator: hines

Post Reply
duytanph
Posts: 6
Joined: Wed Jul 10, 2019 5:03 pm

Parallel NMODL array assignment

Post by duytanph » Thu Oct 17, 2019 9:11 pm

Hello, I am still pretty new to NEURON. I've been trying to look for/come up with a way to set the values of an NMODL array that has the same exact values across many instances of the same NMODL mechanism. The reason is because there is a large array that I would like to use in NMODL but setting the values of that array in Python takes some time. This time to set the values of the array become even more inefficient when I have multiple instances of the same mechanism that need their arrays set to the same values using a double for loop (one loop to iterate across each instance, and another loop for each index of the array).

Here's some dummy code of the NMODL mechanism to illustrate:

Code: Select all

DEFINE NUM_VALS 100           :or some big number


NEURON {
	POINT_PROCESS ARRAY_TEST
	RANGE arr
}


ASSIGNED {
	arr[NUM_VALS]
}


And here's some accompanying Python code for setting ONE instance's array values:

Code: Select all

# create mechanism objects
mech1 = h.ARRAY_TEST(s0(0.5))
mech2 = h.ARRAY_TEST(s0(0.4))

# create numpy array
numpy_array = np.arange(100)

# assign mechanism object's array value
for i in range(100):
	mech1.arr[i] = numpy_array[i]
Note that the array is supposed to be identical, constant, and presumably large (tens of millions of indices) for all instances of the mechanism. One idea I had was to possibly use pointers such that all instances of the mechanism are pointing to the same array in memory, that way I only need to set the same exact address to each instance.

I appreciate any help on this and am open to any other suggestions/methods to accomplish this task. Thanks!

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

Re: Parallel NMODL array assignment

Post by ted » Mon Oct 21, 2019 10:01 am

Use a density mechanism that has a GLOBAL variable. Insert that mechanism into all sections that you want to affect. Use the Vector class's play() method to drive that variable in a single section with the values stored in a single array. Since the variable is GLOBAL, all instances of the density mechanism will be affected. For a practical example of this, see https://www.neuron.yale.edu/ftp/ted/neu ... nd_rec.zip

duytanph
Posts: 6
Joined: Wed Jul 10, 2019 5:03 pm

Re: Parallel NMODL array assignment

Post by duytanph » Thu Oct 24, 2019 6:50 pm

Thanks for the reply, Ted. If I understand correctly, the Vector.play() changes a variable's value based on an array of values with a corresponding time vector which designates WHEN the variable's value is changed. In other words, a SINGLE value is being changed over time. What I believe you were trying to propose was to use GLOBAL in order for every instantiation of the mechanism to see the same changes of a GLOBAL variable (single value) over time.

However, what I am trying to accomplish is more similar to initializing something like a GLOBAL array, in which every instantiation of a certain mechanism has access to the same exact array of values (this array does not change over time/during simulation). Moreover, the initialization of these arrays would take place even before the simulation starts (h.run()) which is why I am unsure if Vector.play() would help in my case.

Have I misread your response perhaps? Hopefully I clarified my situation better. Thank you.

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

Re: Parallel NMODL array assignment

Post by ted » Mon Oct 28, 2019 12:20 pm

Thank you for clarifying your question. To me, the most direct approach would involve a POINTER and a VERBATIM block with a bit of C code that dereferences the proper value in the array. That said, I'll have to pass this on to someone else for an example implementation.

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

Re: Parallel NMODL array assignment

Post by ted » Mon Oct 28, 2019 12:37 pm

One question that may affect the answer: do the values in the array represent breakpoints in a piecewise linear approximation to a function, or are they merely a set of indexed values?

duytanph
Posts: 6
Joined: Wed Jul 10, 2019 5:03 pm

Re: Parallel NMODL array assignment

Post by duytanph » Mon Oct 28, 2019 2:35 pm

I greatly appreciate the efforts. For my purposes, they are simply a set of indexed values. However, I am also curious to see the method that would solve the problem in the breakpoint case as well for future applications. Thank you!

ramcdougal
Posts: 162
Joined: Fri Nov 28, 2008 3:38 pm
Location: Yale School of Public Health

Re: Parallel NMODL array assignment

Post by ramcdougal » Mon Oct 28, 2019 6:05 pm

You can assign your data to a numpy array, get a pointer to the numpy array using neuron.numpy_element_ref, send that pointer to all point processes (this is fast... there's no copying of data), and then have the point process read from the array using a single VERBATIM line.

Our driving Python program:

Code: Select all

import numpy
from neuron import h, numpy_element_ref

soma = h.Section(name='soma')
dend = h.Section(name='dend')

pps = [h.ARRAY_TEST(seg) for seg in [soma(0.5), dend(0.5)]]

# generate 200 data points
data = numpy.random.random(200)

# grab the pointer to the data
ptr = numpy_element_ref(data, 0)

# tell each pp about the pointer
for pp in pps:
    pp._ref_foo = ptr

soma(0.5).v = 14
dend(0.5).v = -43

# have the point process do its thing
h.fadvance()

# for each point process, print the segment, the value calculated, and the value
# if we do the lookup ourselves
for pp in pps:
    print(pp.get_segment(), pp.val, data[int(pp.get_segment().v) + 100])
The MOD file it uses:

Code: Select all

NEURON {
    POINT_PROCESS ARRAY_TEST
    POINTER foo
    RANGE val
}

UNITS {
    (mV) = (millivolt)
}


ASSIGNED {
    v	             (mV)
    foo
    val              (1)
}

BREAKPOINT {
    VERBATIM
    val = _p_foo[(int) _v + 100];
    ENDVERBATIM
}
You can put the VERBATIM block wherever you need to do the lookup. The main thing to know about that line is that if the POINTER variable is called foo, then inside the VERBATIM block, the C pointer is called _p_foo. Likewise regular (non-pointer) variables get prefixed with an _, hence voltage becomes _v. Here I'm casting voltage to an int simply so that the array lookup has an integer offset.

Running the code shows matching values from NEURON doing the lookups and from Python doing the lookups:

Code: Select all

soma(0.5) 0.28198634180594195 0.28198634180594195
dend(0.5) 0.47065239091128874 0.47065239091128874
(The data is random, so your values may vary.)

ramcdougal
Posts: 162
Joined: Fri Nov 28, 2008 3:38 pm
Location: Yale School of Public Health

Re: Parallel NMODL array assignment

Post by ramcdougal » Tue Oct 29, 2019 9:21 am

The above code requires NEURON 7.7.2 or newer.

Older versions won't recognize _ref_foo, and instead need to have the pointer set using h.setpointer; i.e. replace the for loop in the above with:

Code: Select all

# tell each pp about the pointer
for pp in pps:
    h.setpointer(ptr, 'foo', pp)

duytanph
Posts: 6
Joined: Wed Jul 10, 2019 5:03 pm

Re: Parallel NMODL array assignment

Post by duytanph » Thu Oct 31, 2019 3:49 pm

Thank you Ted and Robert for your help! The numpy_element_ref and h.setpointer functions were exactly what I was looking for!

Post Reply