-
Notifications
You must be signed in to change notification settings - Fork 129
Open
Description
Context
In NMODL we have statements like:
FROM i=0 TO N {
...
}
which gets unrolled in NMODL by the LoopUnrollVisitor.
Overview of the issue
If there is a bare loop variable somewhere in an if condition (such as if (i == 0)), NMODL does not unroll it properly. For instance, NMODL reports that this snippet from a KINETIC block:
FROM i = 0 TO 2 {
dsqvol = dsq*vol[i]*0.81
dsqvoler = dsq*vol[i]*0.12
jip3[i] = 0
IF (i == 0) {
~ caip3ri << (dsqvol*jip3[0])
}
jcicr[i] = (vcicr*(ca[i]/(kcicr+ca[i]))*(caer[i]-ca[i]))
~ ca[i] << (dsqvol*jcicr[i])
~ caer[i] << (-dsqvoler*jcicr[i])
}
gets unrolled into:
{
dsqvol = dsq*vol[0]*0.81
dsqvoler = dsq*vol[0]*0.12
jip3[0] = 0
IF (i == 0) {
~ caip3ri << (dsqvol*jip3[0])
}
jcicr[0] = (vcicr*(ca[0]/(kcicr+ca[0]))*(caer[0]-ca[0]))
~ ca[0] << (dsqvol*jcicr[0])
~ caer[0] << (-dsqvoler*jcicr[0])
dsqvol = dsq*vol[1]*0.81
dsqvoler = dsq*vol[1]*0.12
jip3[1] = 0
IF (i == 0) {
~ caip3ri << (dsqvol*jip3[0])
}
jcicr[1] = (vcicr*(ca[1]/(kcicr+ca[1]))*(caer[1]-ca[1]))
~ ca[1] << (dsqvol*jcicr[1])
~ caer[1] << (-dsqvoler*jcicr[1])
dsqvol = dsq*vol[2]*0.81
dsqvoler = dsq*vol[2]*0.12
jip3[2] = 0
IF (i == 0) {
~ caip3ri << (dsqvol*jip3[0])
}
jcicr[2] = (vcicr*(ca[2]/(kcicr+ca[2]))*(caer[2]-ca[2]))
~ ca[2] << (dsqvol*jcicr[2])
~ caer[2] << (-dsqvoler*jcicr[2])
}
which generates broken C++ code since the i is not defined.
Expected result/behavior
It should generate correct code.
Minimal working example - MWE
Probably not minimal, but demonstrates the problem:
NEURON{
SUFFIX cadyn_min
USEION ca READ ica, cai WRITE cai VALENCE 2
USEION caer READ caeri WRITE caeri VALENCE 2
USEION caip3r READ caip3ri WRITE caip3ri VALENCE 2
RANGE ktcicr, kcicr, vcicr
GLOBAL vol
THREADSAFE
}
DEFINE NANN 3
UNITS{
PI = (pi) (1)
}
PARAMETER{
diam (um)
cai0 = 136e-6 (mM)
caeri0 = 0.4 (mM)
: CICR Parameters
kcicr = 0.00198 (mM)
ktcicr = 0.0006 (mM)
vcicr = 5e-7 (/ms)
}
ASSIGNED{
ica (mA/cm2)
cai (mM)
caeri (mM)
vol[NANN] (1)
jip3[NANN] (mM/ms)
jcicr[NANN] (mM/ms)
}
STATE{
ca[NANN] (mM) <1e-8>
caer[NANN] (mM)
caip3ri (mM)
}
INITIAL{
}
BREAKPOINT{
SOLVE state METHOD sparse
ica = 0 : Simplified - no actual current
}
LOCAL frat[NANN]
LOCAL dsq, dsqvol, dsqvoler
KINETIC state {
COMPARTMENT ii, diam*diam*vol[ii]*0.81 {ca}
COMPARTMENT diam*diam*vol[0]*0.81 {caip3ri}
COMPARTMENT jj, diam*diam*vol[jj]*0.12 {caer}
dsq = diam*diam
FROM i=0 TO NANN-1{
dsqvol = dsq*vol[i]*0.81
dsqvoler = dsq*vol[i]*0.12
: Minimal jip3 for the snippet
jip3[i] = 0
if (i==0) {
~ caip3ri << (dsqvol*jip3[0])
}
jcicr[i] = (vcicr* (ca[i]/(kcicr+ca[i])) * (caer[i]-ca[i]) )
~ ca[i] << (dsqvol * jcicr[i])
~ caer[i] << (-dsqvoler * jcicr[i])
}
cai = ca[0]
caeri = caer[0]
}
The above generates correct C++ code with NOCMODL (whether or not it does something stupid is not relevant, this was reduced from this mod file which works).