COMMENT
LUTsyn_NMDA_5th_E3_dtc.mod
This file implements the LUTsyn synapse model described in (Pham, 2021) for NMDA receptors
July 13, 2021
Duy-Tan Jonathan Pham
This software is Copyright © 2021 The University of Southern
California. All Rights Reserved.
Permission to use, copy, modify, and distribute this software
and its documentation for educational, research and non-profit
purposes, without fee, and without a written agreement is
hereby granted, provided that the above copyright notice, this
paragraph and the following three paragraphs appear in all copies.
Permission to make commercial use of this software may be obtained by contacting:
USC Stevens Center for Innovation
University of Southern California
1150 S. Olive Street, Suite 2300
Los Angeles, CA 90115, USA
This software program and documentation are copyrighted by The
University of Southern California. The software program and
documentation are supplied "as is", without any accompanying
services from USC. USC does not warrant that the operation of the
program will be uninterrupted or error-free. The end-user understands
that the program was developed for research purposes and is advised
not to rely exclusively on the program for any reason.
IN NO EVENT SHALL THE UNIVERSITY OF SOUTHERN CALIFORNIA BE
LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE
UNIVERSITY OF SOUTHERN CALIFORNIA HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF SOUTHERN CALIFORNIA
SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
BASIS, AND THE UNIVERSITY OF SOUTHERN CALIFORNIA HAS NO OBLIGATIONS
TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
ENDCOMMENT
NEURON {
POINT_PROCESS LUTsyn_NMDA_5th_E3_dtc
RANGE gain, basis_gain, tau1, tau2, tau3, tau4, t4, t3, t2, t1, t0, MEM, scalar, order, open, gran, index
RANGE g0, g1, g2, alpha, g, e, open_Mg, nbNMDAR, C, B, E, factor, wf, v1
RANGE tc1, tc2, tc3, wtc2, wtc3
RANGE o1_tc1, o1_tc2, o1_tc3, o2_tc1, o2_tc2, o2_tc3, o3_tc1, o3_tc2, o3_tc3, o4_tc1, o4_tc2, o4_tc3, o5_tc1, o5_tc2, o5_tc3
RANGE factor1, factor2, factor3, factor4, factor5
RANGE o1_spks, o2_spks, o3_spks, o4_spks, o5_spks
POINTER gain_array
NONSPECIFIC_CURRENT i
}
UNITS {
(nA) = (nanoamp)
(mV) = (millivolt)
(uS) = (microsiemens)
}
ASSIGNED {
i (nA) : EPSC
gain_array : pointer to look-up table
basis_gain : aka first-order amplitude
gain : dynamically changing amplitude value based on the LUT
tau1 : inter-pulse intervals (IPIs)
tau2
tau3
tau4
t4 : timings of the last 5 pulses
t3
t2
t1
t0
order : indicates the "order" of the present pulse based on timing events
open : open-state probability
gran : granularity in ms
MEM : memory window (normalized by granularity aka ratio R)
index : holds the one-dimensional index to access the LUT array
g : conductance
factor : scaling factor
wf
v1 : membrane voltage (so that python can "access" these values)
wtc3 : weighting factor for triple exponential
o1_spks : counts the number of spikes (pulses) for every order category
o2_spks
o3_spks
o4_spks
o5_spks
}
PARAMETER {
scalar = 1
alpha = 0.01
g0 = 0.0
g1 = 40.0 (pS)
g2 = 247.0 (pS)
Mg = 1
open_Mg = 0.0
v
e = 0
nbNMDAR = 1.235
tc1 = 0.1 (ms)
tc2 = 10 (ms)
tc3 = 11 (ms)
wtc2 = 0.5
o1_tc1 = 1 (ms)
o1_tc2 = 1 (ms)
o1_tc3 = 1 (ms)
factor1 = 1
o2_tc1 = 1 (ms)
o2_tc2 = 1 (ms)
o2_tc3 = 1 (ms)
factor2 = 1
o3_tc1 = 1 (ms)
o3_tc2 = 1 (ms)
o3_tc3 = 1 (ms)
factor3 = 1
o4_tc1 = 1 (ms)
o4_tc2 = 1 (ms)
o4_tc3 = 1 (ms)
factor4 = 1
o5_tc1 = 1 (ms)
o5_tc2 = 1 (ms)
o5_tc3 = 1 (ms)
factor5 = 1
}
INITIAL {
if (tc1/tc2 > .9999) {
tc1 = .9999*tc2
}
if (tc2/tc3 > .9999) {
tc2 = .9999*tc3
}
wtc3 = 1-wtc2
C = 0
B = 0
E = 0
tau1 = -1
tau2 = -1
tau3 = -1
tau4 = -1
t4 = 0
t3 = 0
t2 = 0
t1 = 0
t0 = 0
MEM = 200 :1000/5 (memory window size divided by granularity)
order = 0
index = 0
basis_gain = basis_gain / fabs(scalar)
gain = basis_gain
}
STATE{
C
B
E
}
BREAKPOINT {
SOLVE state METHOD cnexp
: triple exponential model
open = wtc2*B + wtc3*E - C
: simulate the magnesium blockade
g0 = g1 + ((g2 - g1) / (1 + exp(alpha * v * 0.001(1/mV))))
open_Mg = (open) / (1 + exp(-62 * v * 0.001(1/mV)) * Mg / 3.57)
g = g0 * open_Mg * 0.001
i = g * (v-e) * nbNMDAR
v1 = v
}
DERIVATIVE state {
C' = -C/tc1
B' = -B/tc2
E' = -E/tc3
}
NET_RECEIVE(weight (uS)) {
SOLVE update_taus : update the IPI values
SOLVE find_gain : find the LUT amplitude value based on the present IPI values
wf = weight*factor*gain
C = C + wf
B = B + wf
E = E + wf
}
PROCEDURE update_taus(){
: record the last 5 input pulse times
t4 = t3
t3 = t2
t2 = t1
t1 = t0
t0 = t
: adding 0.5 changes the floor function to be a round() function
: convert taus from time delays (ms) into array indices (modified by granularity)
tau1 = floor((t0 - t1)/gran + 0.5)
tau2 = floor((t0 - t2)/gran + 0.5)
tau3 = floor((t0 - t3)/gran + 0.5)
tau4 = floor((t0 - t4)/gran + 0.5)
}
PROCEDURE find_gain(){
: find what ORDER the current pulse is
if ((t0 != 0) && (t1 != 0) && (t2 != 0) && (t3 != 0) && (t4 != 0)) : fifth+ spike case
{
if (tau1 > (MEM - 4)) : first order case
{
order = 1
}
else if (tau2 > (MEM - 3)) : second order case
{
order = 2
}
else if (tau3 > (MEM - 2)) : third order case
{
order = 3
}
else if (tau4 > (MEM-1)): fourth order case
{
order = 4
}
else : fifth order+ case
{
order = 5
}
}
else if (t1 == 0) : first spike case
{
order = 1
}
else if (t2 == 0) : second spike case
{
if (tau1 > (MEM - 4)) : first order case
{
order = 1
}
else : second order case
{
order = 2
}
}
else if (t3 == 0) : third spike case
{
if (tau1 > (MEM - 4)) : first order case
{
order = 1
}
else if (tau2 > (MEM - 3)) : second order case
{
order = 2
}
else : third order case
{
order = 3
}
}
else if (t4 == 0) : fourth spike case
{
if (tau1 > (MEM - 4)) : first order case
{
order = 1
}
else if (tau2 > (MEM - 3)) : second order case
{
order = 2
}
else if (tau3 > (MEM - 2)) : third order case
{
order = 3
}
else :FOURTH ORDER CASE
{
order = 4
}
}
: based on the order, use the appropriate time constants and normalization factor
if (order == 1)
{
gain = basis_gain
tc1 = o1_tc1
tc2 = o1_tc2
tc3 = o1_tc3
factor = factor1
o1_spks = o1_spks + 1
}
else
: convert the multi-dimensional indices into a single one-dimensional index
{
if (order == 2)
{
index = convert_index(tau1,MEM-3,MEM-2,MEM-1)
tc1 = o2_tc1
tc2 = o2_tc2
tc3 = o2_tc3
factor = factor2
o2_spks = o2_spks + 1
}
else if (order == 3)
{
index = convert_index(tau1,tau2,MEM-2,MEM-1)
tc1 = o3_tc1
tc2 = o3_tc2
tc3 = o3_tc3
factor = factor3
o3_spks = o3_spks + 1
}
else if (order == 4)
{
index = convert_index(tau1,tau2,tau3,MEM-1)
tc1 = o4_tc1
tc2 = o4_tc2
tc3 = o4_tc3
factor = factor4
o4_spks = o4_spks + 1
}
else if (order == 5)
{
index = convert_index(tau1,tau2,tau3,tau4)
tc1 = o5_tc1
tc2 = o5_tc2
tc3 = o5_tc3
factor = factor5
o5_spks = o5_spks + 1
}
: use the index to access the look-up table
VERBATIM
gain = ((double*)_p_gain_array)[(int) index];
ENDVERBATIM
}
}
: convert multiple indices into one flattened index
FUNCTION convert_index (ind1, ind2, ind3, ind4){
UNITSOFF
convert_index = ((pow(ind4,4) - 6*pow(ind4,3) + 11*pow(ind4,2) - 6*(ind4))/24 + (pow(ind3,3) - 3*pow(ind3,2) + 2*(ind3))/6 + (pow(ind2,2) - (ind2))/2 + ind1 )
UNITSON
}