Skip to content

cvode no_cap uses direct backing store instead of Node* #3314

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

Merged
merged 38 commits into from
Jun 4, 2025
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ddbee41
cvode scatter/gather use double* instead of data_handle
nrnhines Dec 21, 2024
9f9e5fb
clang format
nrnhines Dec 21, 2024
d7778e2
Lvardt minimize size of CvMembList.ml Memb_list vector.
nrnhines Jan 2, 2025
5c1537b
For lvardt, allow CvMembList.ml.size() > 1 and nodecount > 1
nrnhines Jan 3, 2025
01b4149
fix lvardt segfault when a cvode instance is empty.
nrnhines Jan 4, 2025
d73896e
clang format
nrnhines Jan 5, 2025
f2c2f28
Default node order is cell contiguous (except for thread rootnodes).
nrnhines Jan 4, 2025
18a4aea
Merge remote-tracking branch 'origin/hines/cvscatter-ptr' into hines/…
nrnhines Jan 5, 2025
c8988f1
update to ringtest that supports -method and -2nd_order_thresh
nrnhines Jan 6, 2025
11ba674
incorporate reviewer suggestions
nrnhines Jan 7, 2025
ac1c6a9
Full coverage for this PR.
nrnhines Jan 7, 2025
4f6cba4
Merge branch 'hines/cvlocal-bug' into hines/cell-contiguous
nrnhines Jan 7, 2025
57a987e
Merge branch 'hines/cell-contiguous' into hines/cellcontig+scatter-ptr
nrnhines Jan 7, 2025
8e1e0e5
Merge branch 'master' into hines/cvlocal-bug
nrnhines Jan 8, 2025
7a505e0
Merge branch 'hines/cvlocal-bug' into hines/cell-contiguous
nrnhines Jan 8, 2025
d767760
Merge branch 'hines/cell-contiguous' into hines/cellcontig+scatter-ptr
nrnhines Jan 8, 2025
53010db
For cvode matrix setup/solve use soa storage directly instead of Node**.
nrnhines Jan 9, 2025
f7a2872
fix bug in contiguity constraint
nrnhines Jan 9, 2025
64548b9
cvode no_cap uses direct backing store instead of Node*
nrnhines Jan 14, 2025
89baa0d
Node** v_node_, etc., removed from CvodeThreadData.
nrnhines Jan 14, 2025
35c2687
clang format
nrnhines Jan 14, 2025
2395595
Determine correct thread for Cvode with CvodeThreadData.
nrnhines Jan 19, 2025
bbedc36
Merge branch 'master' into hines/cellcontig-treemat2
nrnhines Jan 19, 2025
96b78c6
Some extra coverage
nrnhines Jan 20, 2025
2123efe
Merge branch 'master' into hines/cellcontig-treemat2
nrnhines Jan 21, 2025
865a22c
Merge branch 'master' into hines/cellcontig-treemat2
nrnhines May 26, 2025
72da2f5
Merge branch 'master' into hines/cellcontig+scatter-ptr
nrnhines May 30, 2025
b265176
Allow special tests with neurondemo. E.g. full coverage for #3454.
nrnhines May 31, 2025
47a5c44
Merge branch 'master' into hines/cellcontig+scatter-ptr
nrnhines May 31, 2025
1690fcb
better comment
nrnhines May 31, 2025
510594b
Merge branch 'master' into hines/cellcontig-treemat2
nrnhines May 31, 2025
22a2ee7
Merge branch 'hines/cellcontig+scatter-ptr' into hines/cellcontig-tre…
nrnhines May 31, 2025
2e126df
The extra run was added with result checking in previous PR.
nrnhines May 31, 2025
190c009
Merge branch 'master' into hines/cellcontig-treemat2
nrnhines Jun 2, 2025
7caee3c
increase coverage by removing never used int NetCvode::cellindex()
nrnhines Jun 2, 2025
12aa723
accept review comments
nrnhines Jun 3, 2025
74141e7
another few pi to parent_i
nrnhines Jun 3, 2025
051f346
Merge branch 'master' into hines/cellcontig-treemat2
nrnhines Jun 3, 2025
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
15 changes: 10 additions & 5 deletions src/nrncvode/cvodeobj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,11 @@ void NetCvode::set_CVRhsFn() {
}
}

static Section* cv_rootsec(const Cvode* cv) {
NrnThread* nt = cv->nth_ ? cv->nth_ : nrn_threads;
return nt->_v_node[cv->ctd_[0].vnode_begin_index_]->sec;
}

int Cvode::cvode_init(double) {
int err = SUCCESS;
// note, a change in stiff_ due to call of stiff() destroys mem_
Expand All @@ -1062,7 +1067,7 @@ int Cvode::cvode_init(double) {
if (err != SUCCESS) {
Printf("Cvode %p %s CVReInit error %d\n",
fmt::ptr(this),
secname(ctd_[0].v_node_[ctd_[0].rootnodecount_]->sec),
secname(cv_rootsec(this)),
err);
return err;
}
Expand All @@ -1078,7 +1083,7 @@ int Cvode::cvode_init(double) {
if (err != SUCCESS) {
Printf("Cvode %p %s CVodeMalloc error %d\n",
fmt::ptr(this),
secname(ctd_[0].v_node_[ctd_[0].rootnodecount_]->sec),
secname(cv_rootsec(this)),
err);
return err;
}
Expand Down Expand Up @@ -1317,7 +1322,7 @@ int Cvode::cvode_advance_tn(neuron::model_sorted_token const& sorted_token) {
if (err < 0) {
Printf("CVode %p %s advance_tn failed, err=%d.\n",
fmt::ptr(this),
secname(ctd_[0].v_node_[ctd_[0].rootnodecount_]->sec),
secname(cv_rootsec(this)),
err);
pf_(t_, y_, nullptr, &opaque);
return err;
Expand Down Expand Up @@ -1360,7 +1365,7 @@ int Cvode::cvode_interpolate(double tout) {
if (err < 0) {
Printf("CVode %p %s interpolate failed, err=%d.\n",
fmt::ptr(this),
secname(ctd_[0].v_node_[ctd_[0].rootnodecount_]->sec),
secname(cv_rootsec(this)),
err);
return err;
}
Expand Down Expand Up @@ -1404,7 +1409,7 @@ void Cvode::statistics() {
#if 1
Printf("\nCvode instance %p %s statistics : %d %s states\n",
fmt::ptr(this),
secname(ctd_[0].v_node_[ctd_[0].rootnodecount_]->sec),
secname(cv_rootsec(this)),
neq_,
(use_daspk_ ? "IDA" : "CVode"));
Printf(" %d advance_tn, %d interpolate, %d init (%d due to at_time)\n",
Expand Down
24 changes: 16 additions & 8 deletions src/nrncvode/cvodeobj.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,29 @@ class CvodeThreadData {
virtual ~CvodeThreadData();
void delete_memb_list(CvMembList*);

int no_cap_count_; // number of nodes with no capacitance
int no_cap_child_count_;
Node** no_cap_node_;
Node** no_cap_child_; // connected to nodes that have no capacitance
std::vector<int> no_cap_indices_;
std::vector<int> no_cap_child_indices_;
CvMembList* cv_memb_list_;
CvMembList* cmlcap_;
CvMembList* cmlext_; // used only by daspk
CvMembList* no_cap_memb_; // used only by cvode, point processes in the no cap nodes
BAMechList* before_breakpoint_;
BAMechList* after_solve_;
BAMechList* before_step_;
int rootnodecount_;
int v_node_count_;
Node** v_node_;
Node** v_parent_;

// Analogous to NrnThread ncell and end to allow similar SoA container
// indexing as in fixed step triang and bksub in nrnoc/solve.cpp.
// The v, rhs, d, a, b, parent storage containers are assumed to be
// sorted for cell contiguity (when lvardt is used) though roots are
// all at the beginning of each thread. The following 4 indices are
// used to directly access regions of those containers for tree setup
// and solving. This eliminates the use of low performance
// Node** v_node_, v_parent_ to access the containers.
int rootnode_begin_index_;
int rootnode_end_index_;
int vnode_begin_index_;
int vnode_end_index_;

PreSynList* psl_th_; // with a threshold
std::list<WatchCondition*>* watch_list_;
// since scatter/gather are hot loops, don't want to use data_handle
Expand Down
98 changes: 55 additions & 43 deletions src/nrncvode/cvtrset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,35 @@ void Cvode::rhs(neuron::model_sorted_token const& sorted_token, NrnThread* _nt)
if (diam_changed) {
recalc_diam();
}
if (z.v_node_count_ == 0) {
if (z.rootnode_end_index_ == 0) {
return;
}
for (int i = 0; i < z.v_node_count_; ++i) {
NODERHS(z.v_node_[i]) = 0.;
auto* const vec_rhs = _nt->node_rhs_storage();
for (int i = z.rootnode_begin_index_; i < z.rootnode_end_index_; ++i) {
vec_rhs[i] = 0.;
}
for (int i = z.vnode_begin_index_; i < z.vnode_end_index_; ++i) {
vec_rhs[i] = 0.;
}
auto const vec_sav_rhs = _nt->node_sav_rhs_storage();
if (vec_sav_rhs) {
for (int i = 0; i < z.v_node_count_; ++i) {
Node* nd = z.v_node_[i];
vec_sav_rhs[nd->v_node_index] = 0;
for (int i = z.rootnode_begin_index_; i < z.rootnode_end_index_; ++i) {
vec_sav_rhs[i] = 0.;
}
for (int i = z.vnode_begin_index_; i < z.vnode_end_index_; ++i) {
vec_sav_rhs[i] = 0.;
}
}

rhs_memb(sorted_token, z.cv_memb_list_, _nt);
auto const vec_rhs = _nt->node_rhs_storage();
nrn_nonvint_block_current(_nt->end, vec_rhs, _nt->id);

if (vec_sav_rhs) {
for (int i = 0; i < z.v_node_count_; ++i) {
auto const node_index = z.v_node_[i]->v_node_index;
vec_sav_rhs[node_index] -= vec_rhs[node_index];
for (int i = z.rootnode_begin_index_; i < z.rootnode_end_index_; ++i) {
vec_sav_rhs[i] -= vec_rhs[i];
}
for (int i = z.vnode_begin_index_; i < z.vnode_end_index_; ++i) {
vec_sav_rhs[i] -= vec_rhs[i];
}
}

Expand All @@ -46,13 +53,13 @@ void Cvode::rhs(neuron::model_sorted_token const& sorted_token, NrnThread* _nt)
auto const vec_a = _nt->node_a_storage();
auto const vec_b = _nt->node_b_storage();
auto const vec_v = _nt->node_voltage_storage();
for (auto i = z.rootnodecount_; i < z.v_node_count_; ++i) {
auto const node_i = z.v_node_[i]->v_node_index;
auto const parent_i = z.v_parent_[i]->v_node_index;
auto const dv = vec_v[parent_i] - vec_v[node_i];
// our connection coefficients are negative
vec_rhs[node_i] -= vec_b[node_i] * dv;
vec_rhs[parent_i] += vec_a[node_i] * dv;
auto* const parents = _nt->_v_parent_index;
for (int i = z.vnode_begin_index_; i < z.vnode_end_index_; ++i) {
auto const parent_i = parents[i];
auto const dv = vec_v[parent_i] - vec_v[i];
// our connection coefficients are negative so
vec_rhs[i] -= vec_b[i] * dv;
vec_rhs[parent_i] += vec_a[i] * dv;
}
}

Expand Down Expand Up @@ -80,11 +87,15 @@ void Cvode::lhs(neuron::model_sorted_token const& sorted_token, NrnThread* _nt)
int i;

CvodeThreadData& z = CTD(_nt->id);
if (z.v_node_count_ == 0) {
if (z.rootnode_end_index_ == 0) {
return;
}
for (i = 0; i < z.v_node_count_; ++i) {
NODED(z.v_node_[i]) = 0.;
auto* const vec_d = _nt->node_d_storage();
for (int i = z.rootnode_begin_index_; i < z.rootnode_end_index_; ++i) {
vec_d[i] = 0.;
}
for (int i = z.vnode_begin_index_; i < z.vnode_end_index_; ++i) {
vec_d[i] = 0.;
}

lhs_memb(sorted_token, z.cv_memb_list_, _nt);
Expand All @@ -96,11 +107,12 @@ void Cvode::lhs(neuron::model_sorted_token const& sorted_token, NrnThread* _nt)
// fast_imem not needed since exact icap added in nrn_div_capacity

/* now add the axial currents */
for (i = 0; i < z.v_node_count_; ++i) {
NODED(z.v_node_[i]) -= NODEB(z.v_node_[i]);
}
for (i = z.rootnodecount_; i < z.v_node_count_; ++i) {
NODED(z.v_parent_[i]) -= NODEA(z.v_node_[i]);
auto* const vec_a = _nt->node_a_storage();
auto* const vec_b = _nt->node_b_storage();
auto* const parent_i = _nt->_v_parent_index;
for (int i = z.vnode_begin_index_; i < z.vnode_end_index_; ++i) {
vec_d[i] -= vec_b[i];
vec_d[parent_i[i]] -= vec_a[i];
}
}

Expand All @@ -125,33 +137,33 @@ void Cvode::lhs_memb(neuron::model_sorted_token const& sorted_token,

/* triangularization of the matrix equations */
void Cvode::triang(NrnThread* _nt) {
Node *nd, *pnd;
double p;
int i;
CvodeThreadData& z = CTD(_nt->id);

for (i = z.v_node_count_ - 1; i >= z.rootnodecount_; --i) {
nd = z.v_node_[i];
pnd = z.v_parent_[i];
p = NODEA(nd) / NODED(nd);
NODED(pnd) -= p * NODEB(nd);
NODERHS(pnd) -= p * NODERHS(nd);
auto* const vec_a = _nt->node_a_storage();
auto* const vec_b = _nt->node_b_storage();
auto* const vec_d = _nt->node_d_storage();
auto* const vec_rhs = _nt->node_rhs_storage();
for (int i = z.vnode_end_index_ - 1; i >= z.vnode_begin_index_; --i) {
double const p = vec_a[i] / vec_d[i];
auto const parent_i = _nt->_v_parent_index[i];
vec_d[parent_i] -= p * vec_b[i];
vec_rhs[parent_i] -= p * vec_rhs[i];
}
}

/* back substitution to finish solving the matrix equations */
void Cvode::bksub(NrnThread* _nt) {
Node *nd, *cnd;
int i;
CvodeThreadData& z = CTD(_nt->id);

for (i = 0; i < z.rootnodecount_; ++i) {
NODERHS(z.v_node_[i]) /= NODED(z.v_node_[i]);
auto* const vec_b = _nt->node_b_storage();
auto* const vec_d = _nt->node_d_storage();
auto* const vec_rhs = _nt->node_rhs_storage();
auto* const parent_i = _nt->_v_parent_index;
for (int i = z.rootnode_begin_index_; i < z.rootnode_end_index_; ++i) {
vec_rhs[i] /= vec_d[i];
}
for (i = z.rootnodecount_; i < z.v_node_count_; ++i) {
cnd = z.v_node_[i];
nd = z.v_parent_[i];
NODERHS(cnd) -= NODEB(cnd) * NODERHS(nd);
NODERHS(cnd) /= NODED(cnd);
for (int i = z.vnode_begin_index_; i < z.vnode_end_index_; ++i) {
vec_rhs[i] -= vec_b[i] * vec_rhs[parent_i[i]];
vec_rhs[i] /= vec_d[i];
}
}
Loading
Loading