Skip to content

Commit

Permalink
Merge branch 'master' into cornu/create_logger_class
Browse files Browse the repository at this point in the history
  • Loading branch information
alkino authored Oct 1, 2024
2 parents 3eaeb55 + 95cc05b commit 4110370
Show file tree
Hide file tree
Showing 7 changed files with 272 additions and 6 deletions.
90 changes: 90 additions & 0 deletions share/demo/release/capmpr.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
: capump.mod plus a "reservoir" used to initialize cai to desired concentrations

UNITS {
(mM) = (milli/liter)
(mA) = (milliamp)
(um) = (micron)
(mol) = (1)
PI = (pi) (1)
FARADAY = (faraday) (coulomb)
}

NEURON {
SUFFIX capmpr
USEION ca READ cao, cai WRITE cai, ica
GLOBAL k1, k2, k3, k4
GLOBAL car, tau
}

STATE {
pump (mol/cm2)
pumpca (mol/cm2)
cai (mM)
}

PARAMETER {
car = 5e-5 (mM) : ca in reservoir, used to initialize cai to desired concentrations
tau = 1e9 (ms) : rate of equilibration between cai and car

k1 = 5e8 (/mM-s)
k2 = .25e6 (/s)
k3 = .5e3 (/s)
k4 = 5e0 (/mM-s)

pumpdens = 3e-14 (mol/cm2)
}

CONSTANT {
volo = 1 (liter)
}

ASSIGNED {
diam (um)
cao (mM)

ica (mA/cm2)
ipump (mA/cm2)
ipump_last (mA/cm2)
voli (um3)
area1 (um2)
c1 (1+8 um5/ms)
c2 (1-10 um2/ms)
c3 (1-10 um2/ms)
c4 (1+8 um5/ms)
}

BREAKPOINT {
SOLVE pmp METHOD sparse
ipump_last = ipump
ica = ipump
}

KINETIC pmp {
COMPARTMENT voli {cai}
COMPARTMENT (1e10)*area1 {pump pumpca}
COMPARTMENT volo*(1e15) {cao car}

~ car <-> cai (1(um3)/tau,1(um3)/tau)
~ cai + pump <-> pumpca (c1,c2)
~ pumpca <-> pump + cao (c3,c4)

: note that forward flux here is the outward flux
ipump = (1e-4)*2*FARADAY*(f_flux - b_flux)/area1

: ipump_last vs ipump needed because of STEADYSTATE calculation
~ cai << (-(ica - ipump_last)*area1/(2*FARADAY)*(1e4))

CONSERVE pump + pumpca = (1e10)*area1*pumpdens
}

INITIAL {
:cylindrical coordinates; actually vol and area1/unit length
voli = PI*(diam/2)^2 * 1(um)
area1 = 2*PI*(diam/2) * 1(um)
c1 = (1e7)*area1 * k1
c2 = (1e7)*area1 * k2
c3 = (1e7)*area1 * k3
c4 = (1e7)*area1 * k4

SOLVE pmp STEADYSTATE sparse
}
2 changes: 1 addition & 1 deletion src/ivoc/apwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ bool PrintableWindow::receive(const Event& e) {
reconfigured();
notify();
break;
// LCOV_EXCL_END
// LCOV_EXCL_STOP
case MapNotify:
if (xplace_) {
if (xtop() != xtop_ || xleft() != xleft_) {
Expand Down
2 changes: 1 addition & 1 deletion src/ivoc/pwman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1477,7 +1477,7 @@ void PrintableWindow::reconfigured() {
xmove(x, y);
}
}
// LCOV_EXCL_END
// LCOV_EXCL_STOP

void ViewWindow::reconfigured() {
if (!pixres) {
Expand Down
7 changes: 4 additions & 3 deletions src/nrnoc/eion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,9 +430,10 @@ void nrn_check_conc_write(Prop* p_ok, Prop* pion, int i) {
}
for (k = 0, j = 0; j < n_memb_func; ++j) {
if (nrn_is_ion(j)) {
ion_bit_[j] = (1 << k);
++k;
assert(k < max_ions);
ion_bit_[j].reset();
ion_bit_[j].set(k);
++k;
}
}

Expand Down Expand Up @@ -640,7 +641,7 @@ void second_order_cur(NrnThread* nt) {
extern int secondorder;
NrnThreadMembList* tml;
Memb_list* ml;
int j, i, i2;
int i, i2;
constexpr auto c = 3;
constexpr auto dc = 4;
if (secondorder == 2) {
Expand Down
2 changes: 1 addition & 1 deletion src/sundials/cvodes/cvodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3285,7 +3285,7 @@ static int CVStep(CVodeMem cv_mem)
dsm = CVStgrUpdateDsm(cv_mem, dsm, dsmS);
}
}
// LCOV_EXCL_END
// LCOV_EXCL_STOP
/* Everything went fine; exit loop */
break;

Expand Down
62 changes: 62 additions & 0 deletions test/hoctests/tests/test_eion_cover.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from neuron import h
from neuron.expect_hocerr import expect_err, set_quiet

set_quiet(0)
from math import isclose


def test_nernst():
assert h.nernst(1, 1, 0) == 0.0
assert h.nernst(-1, 1, 1) == 1e6
assert h.nernst(1, -1, 1) == -1e6

s = h.Section()
s.insert("hh")
assert isclose(h.nernst("ena", sec=s), 63.55150321937486)
assert isclose(h.nernst("ena", 0.5, sec=s), 63.55150321937486)
assert isclose(h.nernst("nai", sec=s), 17.554820246530547)
assert isclose(h.nernst("nao", sec=s), 79.7501757545304)
expect_err('h.nernst("ina", sec=s)')

del s
locals()


def test_ghk():
assert isclose(h.ghk(-10, 0.1, 10, 2), -2828.3285716150644)
assert isclose(h.ghk(1e-6, 0.1, 10, 2), -1910.40949510667)


def test_ion_style():
expect_err('h.ion_style("foo")')


def test_second_order_cur():
s = h.Section()
s.insert("hh")
h.secondorder = 2
h.finitialize(-65)
h.fadvance()
assert isclose(s(0.5).ina, -0.001220053188847315)
h.secondorder = 0
h.finitialize(-65)
h.fadvance()
assert isclose(s(0.5).ina, -0.0012200571764654333)


def test_ion_charge():
assert h.ion_charge("na_ion") == 1
expect_err('h.ion_charge("na") == 1')


def test_eion_cover():
test_nernst()
test_ghk()
test_ion_style()
test_second_order_cur()
test_ion_charge()


if __name__ == "__main__":
test_eion_cover()
h.topology()
113 changes: 113 additions & 0 deletions test/hoctests/tests/test_neurondemo.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
dir_path = os.path.dirname(os.path.realpath(__file__))
chk = Chk(os.path.join(dir_path, "test_neurondemo.json"))


# Run a command with input into stdin
def run(cmd, input):
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, text=True)
Expand Down Expand Up @@ -47,6 +48,7 @@ def run(cmd, input):
quit()
"""


# run neurondemo and return the stdout lines between ZZZbegin and ZZZend
def neurondemo(extra, input):
input = extra + input
Expand Down Expand Up @@ -172,3 +174,114 @@ def neurondemo(extra, input):
chk(key, rich_data)

chk.save()

################################################
# test_many_ions.py copied below and removed to fix a CI coverage test failure:
# libgcov profiling error:/home/...demo/release/x86_64/mod_func.gcda:overwriting
# an existing profile data with a different timestamp.
# I was unable to reproduce the coverage test failure on my linux desktop by
# experimenting with parallel runs of the distinct tests. Nevertheless,
# CI coverage is successful when the use of the neurondemo shared library is
# serialized into this file.
# I'd rather keep the file and run from here via something like
# run("python test_many_ions.py", "")
# but cmake installs each hoctest file in a separate folder and "python" may not
# be the name of the program we need to run.
###########################
# Test when large number of ion mechanisms exist.

# Strategy is to create a large number of ion mechanisms before loading
# the neurondemo mod file shared library which will create the ca ion
# along with several mechanisms that write to cai.

from neuron import h, load_mechanisms
from platform import machine
import sys
import io


# return True if name exists in h
def exists(name):
try:
exec("h.%s" % name)
except:
return False
return True


# use up a large number of mechanism indices for ions. And want to test beyond
# 1000 which requires change to max_ions in nrn/src/nrnoc/eion.cpp
nion = 250
ion_indices = [int(h.ion_register("ca%d" % i, 2)) for i in range(1, nion + 1)]
# gain some confidence they exist
assert exists("ca%d_ion" % nion)
assert (ion_indices[-1] - ion_indices[0]) == (nion - 1)
mt = h.MechanismType(0)
assert mt.count() > nion

# this test depends on the ca ion not existing at this point
assert exists("ca_ion") is False

# load neurondemo mod files. That will create ca_ion and provide two
# mod files that write cai
# Following Aborts prior to PR#3055 with
# eion.cpp:431: void nrn_check_conc_write(Prop*, Prop*, int): Assertion `k < sizeof(long) * 8' failed.
nrnmechlibpath = "%s/demo/release" % h.neuronhome()
print(nrnmechlibpath)
assert load_mechanisms(nrnmechlibpath)

# ca_ion now exists and has a mechanism index > nion
assert exists("ca_ion")
mt = h.MechanismType(0) # new mechanisms do not appear in old MechanismType
mt.select("ca_ion")
assert mt.selected() > nion


# return stderr output resulting from sec.insert(mechname)
def mech_insert(sec, mechname):
# capture stderr
old_stderr = sys.stderr
sys.stderr = mystderr = io.StringIO()

sec.insert(mechname)

sys.stderr = old_stderr
return mystderr.getvalue()


# test if can use the high mechanism index cadifpmp (with USEION ... WRITE cai) along with the high mechanims index ca_ion
s = h.Section()
s.insert("cadifpmp")
h.finitialize(-65)
# The ion_style tells whether cai or cao is being written
istyle = int(h.ion_style("ca_ion", sec=s))
assert istyle & 0o200 # writing cai
assert (istyle & 0o400) == 0 # not writing ca0
# unfortunately, at present, uninserting does not turn off that bit
s.uninsert("cadifpmp")
assert s.has_membrane("cadifpmp") is False
assert int(h.ion_style("ca_ion", sec=s)) & 0o200
# nevertheless, on reinsertion, there is no warning, so can't test the
# warning without a second mechanism that WRITE cai
assert mech_insert(s, "cadifpmp") == ""
assert s.has_membrane("cadifpmp")
# uninsert again and insert another mechanism that writes.
s.uninsert("cadifpmp")
assert mech_insert(s, "capmpr") == "" # no warning
assert mech_insert(s, "cadifpmp") != "" # now there is a warning.

# more serious test
# several sections with alternating cadifpmp and capmpr
del s
secs = [h.Section() for i in range(5)]
for i, s in enumerate(secs):
if i % 2:
assert mech_insert(s, "capmpr") == ""
else:
assert mech_insert(s, "cadifpmp") == ""

# warnings due to multiple mechanisms at same location that WRITE cai
assert mech_insert(secs[2], "capmpr") != ""
assert mech_insert(secs[3], "cadifpmp") != ""

############################################

0 comments on commit 4110370

Please sign in to comment.