Thread-safe non-voltage POINTER variables

General issues of interest both for network and
individual cell parallelization.

Moderator: hines

Post Reply
rahy
Posts: 2
Joined: Wed May 31, 2023 11:38 am

Thread-safe non-voltage POINTER variables

Post by rahy »

Hello,

The network I'm working on involves custom-written mechanisms with non-voltage variables that need to be communicated bidirectionally between multiple synaptic mechanisms and a diffusion mechanism. Specifically, I'm trying to implement an eligibility-trace-based plasticity mechanism that combines trace inputs from multiple synapse types. So far I'd implemented this using POINTERS, such that the synapses can increment these traces when an event comes in, which can then decay and diffuse throughout the membrane.

My problem is that my setup takes too long to run so I'd like to parallelize it. As far as I can tell, the only way to make these mechanisms thread-safe would be to replace the POINTERS with the ParallelContext source_var/target_var combination. This, however, is an obviously unidirectional connection, and I need changes in these variables in either the cell or the synapses to be communicated between the two. I've tried using source_var/target_var in both directions, to connect the cell sections to their corresponding POINT_PROCESS and vice versa, followed by pc.setup_transfer(). While this leads to more or less the same results as using POINTERS when running over a single thread, it fails immediately when running over multiple threads (as specified though the GUI): the program crashes if I don't specify the target component in all target_var functions (which is required for multi-threading), but also crashes if I specify that some of the targets are cell dendrite sections and not point processes. Am I missing something? Is there any other way to make this work?

Thank you!
hines
Site Admin
Posts: 1682
Joined: Wed May 18, 2005 3:32 pm

Re: Thread-safe non-voltage POINTER variables

Post by hines »

I'm afraid the model that coelesced in my mind after reading your post
is unlikely to be the same as your existing (working serial?) model.
I'm imagining a few states per compartment of a cell that are coupled to
the corresponding states of adjacent compartments of the same cell via
fluxes that are more or less proportional to the difference in adjacent
state values (aka a reaction diffusion system). When an event arrives
at a synapse, a discontinuous change takes place in (one?) of the states
in the compartment where the synapse is located. If this is correct,
Robert can weigh in with regard to whether the RxD module can represent
the details of your "diffusion mechanism". However, it is not clear to
me that your pointers are not threadsafe to begin with. It is typically
the case that whole cells exist in a single thread. Or is your
situation such that variables are coupled continuously between different
cells analogous to gap junctions) instead of by discrete events with
delay?
ramcdougal
Posts: 267
Joined: Fri Nov 28, 2008 3:38 pm
Location: Yale School of Public Health

Re: Thread-safe non-voltage POINTER variables

Post by ramcdougal »

I'm not sure if I understand enough of what's happening to be able to say if NEURON's rxd mechanism would be useful...

... but you may want to check out the MOD file in Figure 13 of doi:10.3389/fninf.2022.847108 and the surrounding discussion. There we have a synapse that receives event-driven input that causes a flux that introduces new mass into the cell that then diffuses out.
rahy
Posts: 2
Joined: Wed May 31, 2023 11:38 am

Re: Thread-safe non-voltage POINTER variables

Post by rahy »

At the moment, my model is limited to only one cell receiving inputs from artificial cells, but that one cell is so huge that the simulation already takes too long to run serially, which is why I'd like to be able to parallelize it (using multisplit?) before expanding the network further. I'm not sure I managed to explain my model correctly though, so here are some more details about what we're actually trying to do:

What I'm trying to implement is a form of plasticity that is based on the time of last spike in that synapse, similar to standard STDP. However, instead of having this plasticity be limited to the synapse that receives the spike, we need that for plasticity to be able to "spread" throughout the cell. For example if a spike comes in at one compartment, we want the plasticity to not only affect the synapse at that compartment but to also be able to spread throughout the cell and affect other synapses.

To do this, we've decided to define multiple mechanisms that basically boil down to this: creating an eligibility trace variable, where the eligibility trace is treated an actual trace (in nanosiemens) that can decay and defuse throughout the cell. Crucially, this trace is calculated as the result of contributions of synaptic events coming in from multiple cell types in an attempt to describe 3-part Hebbian learning, and would then be used to calculate incrementations in the weights at different synapses.

Threrefore, we've added on top of the HH mechanism in the cell a cellular mechanism that has a variable for an eligibility trace, whose decay/diffusion dynamics are defined in the KINETIC block.

Once an event arrives at a synapse, the trace at the corresponding cellular compartment is incremented by a certain value delta, indicating increased eligibility for plasticity. As the trace then decays, this change diffuses throughout the cell, and its value is used to increment the weights of the synapses that are connected to the compartments it "reaches".

The problem with this is that both the cellular mechanism and the synapses themselves need access to the eligibility trace variable: the cellular mechanism to allow diffusion, and the synaptic mechanism to increment the trace according to the synapse cell type and to use the value of the trace to increment its weight. I'd implemented this using POINTER variables, but that crashed the program once I tried to use multithreading due to pointers not being thread-safe. As described in my first post, I tried to use the ParallelContext source_var/target_var functions, but I cannot get it to create a bidirectional connection, where the value of the variable can be read and changed by both the cell and the synapse, without the program crashing again.

This is not a fully-detailed version, but I hope it gives a better picture of what the model is?
hines
Site Admin
Posts: 1682
Joined: Wed May 18, 2005 3:32 pm

Re: Thread-safe non-voltage POINTER variables

Post by hines »

Multisplit will not provide a complete parallel solution as it is limited to voltage as the coupling variable between compartments. However it does suffice for the stiff (very small time constants can be a source of numerical instability and voltage coupling between small compartments is very large) voltage coupling part of the problem by solving the entire tree with implicit backward euler methods. I don't know the spatial extent of your "trace variable" but diffusion is generally very slow compared to voltage propagation. Also it may be that you can use regional traces for subtrees and just connect the traces by analogy to gap junctions. At any rate if you envision going to networks of these cells where there are many more cells than threads or MPI ranks then
it there is no purpose for multisplit as whole cells are easier to balance and manage.

Anyway, I would perhaps implement the trace with a USEION statement as that provides longitudinal diffusion and makes it easy for a synapse to
increment the local concentration (via a current) in response to an event. I would expect CVode to be very effective, accuracy and performance wise, until
your computational experiments got to the point where the density of arriving events on the cell is more that one per fixed time step.
If the ion is called tr, the the relevant concentration is tri and the relevant current is itr. For the synapse all you need is
USEION tr WRITE itr
or, rather, if you synapse is plastic
USEION tr READ tri WRITE itr
so that you can use tri to determine how much to modify the synaptic weight variables.

And for the diffusion mechanism all you need is
USEION tr READ itr WRITE tri
The diffusion mechanism could be implemented in RxD or in a MOD file with a KINETIC scheme and LONGITUDINAL_DIFFUSION.

No need for POINTER
Post Reply