Page 1 of 1

Parallel NMODL array assignment

Posted: Thu Oct 17, 2019 9:11 pm
by duytanph
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!

Re: Parallel NMODL array assignment

Posted: Mon Oct 21, 2019 10:01 am
by ted
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

Re: Parallel NMODL array assignment

Posted: Thu Oct 24, 2019 6:50 pm
by duytanph
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.

Re: Parallel NMODL array assignment

Posted: Mon Oct 28, 2019 12:20 pm
by ted
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.

Re: Parallel NMODL array assignment

Posted: Mon Oct 28, 2019 12:37 pm
by ted
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?

Re: Parallel NMODL array assignment

Posted: Mon Oct 28, 2019 2:35 pm
by duytanph
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!

Re: Parallel NMODL array assignment

Posted: Mon Oct 28, 2019 6:05 pm
by ramcdougal
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.)

Re: Parallel NMODL array assignment

Posted: Tue Oct 29, 2019 9:21 am
by ramcdougal
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)

Re: Parallel NMODL array assignment

Posted: Thu Oct 31, 2019 3:49 pm
by duytanph
Thank you Ted and Robert for your help! The numpy_element_ref and h.setpointer functions were exactly what I was looking for!