Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test for PR 3055 #3081

Merged
merged 25 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4232cab
increased maximum number of ions per compartment by using std::bitset…
wthun Aug 22, 2024
5179cc4
changed vector.reserve to vector.resize to initialize std::bitset ele…
wthun Aug 23, 2024
61162e4
cleanup
wthun Aug 23, 2024
25fa1aa
Merge branch 'master' into hines/ions
nrnhines Sep 18, 2024
3c01089
test of high mechanism index ions and mechanisms
nrnhines Sep 19, 2024
7ccc143
Fix formatting
github-actions[bot] Sep 19, 2024
fb2d01a
Merge branch 'master' into master
1uc Sep 20, 2024
fc27477
rename max_length to max_ion
wthun Sep 20, 2024
e36452c
Update src/nrnoc/eion.cpp
wthun Sep 20, 2024
3b5e359
Update src/nrnoc/eion.cpp
wthun Sep 20, 2024
dc47da5
Update src/nrnoc/eion.cpp
wthun Sep 20, 2024
570a9ae
cmake-format
wthun Sep 20, 2024
dc11e93
increased max_ion to 256
wthun Sep 20, 2024
7293b78
Merge remote-tracking branch 'forked/master' into hines/ions
nrnhines Sep 20, 2024
3f5c418
Temporarily adjust test to create 250 ions.
nrnhines Sep 20, 2024
da974c2
Merge branch 'master' into hines/ions
nrnhines Sep 20, 2024
3f213b0
Use generic mod file loader
nrnhines Sep 20, 2024
23071ee
ion_bit_ can have many bits.
nrnhines Sep 20, 2024
6604aab
For bitset single bit, first reset, then set the bit.
nrnhines Sep 20, 2024
0d087b7
Add another mod file to neurondemo that WRITE cai. More testing.
nrnhines Sep 21, 2024
bfc82da
eion.cpp -Wall free
nrnhines Sep 21, 2024
ebf26b1
eion.cpp coverage 100% functions 94% lines
nrnhines Sep 22, 2024
06f9ace
Replace // LCOV_EXCL_END with // LCOV_EXCL_STOP
nrnhines Sep 22, 2024
74d6029
Merge branch 'master' into hines/ions
nrnhines Sep 26, 2024
1318a3f
Fix the CI test coverage failure.
nrnhines Sep 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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") != ""

############################################
Loading