void Cvode::maxstate(bool b, NrnThread* nt) { if (!maxstate_) { return; } if (!nt) { if (nrn_nthread > 1) { maxstate_cv = this; maxstate_b = b; nrn_multithread_job(maxstate_thread); return; } nt = nrn_threads; } CvodeThreadData& z = ctd_[nt->id]; int i; double x; double* y = n_vector_data(y_, nt->id); double* m = n_vector_data(maxstate_, nt->id); for (i=0; i < z.nvsize_; ++i) { x = Math::abs(y[i]); if (m[i] < x) { m[i] = x; } } if (b) { y = n_vector_data(acorvec(), nt->id); m = n_vector_data(maxacor_, nt->id); for (i=0; i < z.nvsize_; ++i) { x = Math::abs(y[i]); if (m[i] < x) { m[i] = x; } } } }
void Cvode::error_weights(double* pd) { int i, id; for (id=0; id < nctd_; ++id) { CvodeThreadData& z = ctd_[id]; double* s = n_vector_data(ewtvec(), id); for (i=0; i < z.nvsize_; ++i) { pd[i + z.nvoffset_] = s[i]; } } }
void Cvode::states(double* pd) { int i, id; for (id=0; id < nctd_; ++id) { CvodeThreadData& z = ctd_[id]; double* s = n_vector_data(y_, id); for (i=0; i < z.nvsize_; ++i) { pd[i + z.nvoffset_] = s[i]; } } }
void Cvode::acor(double* pd) { int i, id; NrnThread* nt; for (id=0; id < nctd_; ++id) { CvodeThreadData& z = ctd_[id]; double* s = n_vector_data(acorvec(), id); for (i=0; i < z.nvsize_; ++i) { pd[i + z.nvoffset_] = s[i]; } } }
void Cvode::maxacor(double* pd) { int i; NrnThread* nt; if (maxacor_) { FOR_THREADS(nt) { double* m = n_vector_data(maxacor_, nt->id); int n = ctd_[nt->id].nvsize_; int o = ctd_[nt->id].nvoffset_; for (i=0; i < n; ++i) { pd[i+o] = m[i]; } } } }
void Cvode::daspk_init_eqn(){ // DASPK equation order is exactly the same order as the // fixed step method for current balance (including // extracellular nodes) and linear mechanism. Remaining ode // equations are same order as for Cvode. Thus, daspk differs from // cvode order primarily in that cap and no-cap nodes are not // distinguished. // note that only one thread is allowed for sparse right now. NrnThread* _nt = nrn_threads; CvodeThreadData&z = ctd_[0]; double vtol; //printf("Cvode::daspk_init_eqn\n"); int i, j, in, ie, k, neq_v; // how many equations are there? Memb_func* mf; CvMembList* cml; //start with all the equations for the fixed step method. if (use_sparse13 == 0 || diam_changed != 0) { recalc_diam(); } z.neq_v_ = spGetSize(_nt->_sp13mat, 0); z.nvsize_ = z.neq_v_; // now add the membrane mechanism ode's to the count for (cml = z.cv_memb_list_; cml; cml = cml->next) { Pfridot s = (Pfridot)memb_func[cml->index].ode_count; if (s) { z.nvsize_ += cml->ml->nodecount * (*s)(cml->index); } } neq_ = z.nvsize_; //printf("Cvode::daspk_init_eqn: neq_v_=%d neq_=%d\n", neq_v_, neq_); if (z.pv_) { delete [] z.pv_; delete [] z.pvdot_; } z.pv_ = new double*[z.nvsize_]; z.pvdot_ = new double*[z.nvsize_]; atolvec_alloc(neq_); double* atv = n_vector_data(atolnvec_, 0); for (i=0; i < neq_; ++i) { atv[i] = ncv_->atol(); } vtol = 1.; if (!vsym) { vsym = hoc_table_lookup("v", hoc_built_in_symlist); } if (vsym->extra) { double x; x = vsym->extra->tolerance; if (x != 0 && x < vtol) { vtol = x; } } // deal with voltage and extracellular and linear circuit nodes // for daspk the order is the same assert(use_sparse13); if (use_sparse13) { for (in = 0; in < _nt->end; ++in) { Node* nd; Extnode* nde; nd = _nt->_v_node[in]; nde = nd->extnode; i = nd->eqn_index_ - 1; // the sparse matrix index starts at 1 z.pv_[i] = &NODEV(nd); z.pvdot_[i] = nd->_rhs; if (nde) { for (ie=0; ie < nlayer; ++ie) { k = i + ie + 1; z.pv_[k] = nde->v + ie; z.pvdot_[k] = nde->_rhs[ie]; } } } linmod_dkmap(z.pv_, z.pvdot_); for (i=0; i < z.neq_v_; ++i) { atv[i] *= vtol; } } // map the membrane mechanism ode state and dstate pointers int ieq = z.neq_v_; for (cml = z.cv_memb_list_; cml; cml = cml->next) { int n; mf = memb_func + cml->index; Pfridot sc = (Pfridot)mf->ode_count; if (sc && ( (n = (*sc)(cml->index)) > 0)) { Memb_list* ml = cml->ml; Pfridot s = (Pfridot)mf->ode_map; if (mf->hoc_mech) { for (j=0; j < ml->nodecount; ++j) { (*s)(ieq, z.pv_ + ieq, z.pvdot_ + ieq, ml->prop[j], atv + ieq); ieq += n; } }else{ for (j=0; j < ml->nodecount; ++j) { (*s)(ieq, z.pv_ + ieq, z.pvdot_ + ieq, ml->data[j], ml->pdata[j], atv + ieq, cml->index); ieq += n; } } } } structure_change_ = false; }
void Cvode::init_eqn(){ double vtol; NrnThread* _nt; CvMembList* cml; Memb_list* ml; Memb_func* mf; int i, j, zneq, zneq_v, zneq_cap_v; //printf("Cvode::init_eqn\n"); if (nthsizes_) { delete [] nthsizes_; nthsizes_ = 0; } neq_ = 0; for (int id = 0; id < nctd_; ++id) { CvodeThreadData& z = ctd_[id]; z.cmlcap_ = nil; z.cmlext_ = nil; for (cml = z.cv_memb_list_; cml; cml = cml->next) { if (cml->index == CAP) { z.cmlcap_ = cml; } if (cml->index == EXTRACELL) { z.cmlext_ = cml; } } } if (use_daspk_) { daspk_init_eqn(); return; } FOR_THREADS(_nt) { // for lvardt, this body done only once and for ctd_[0] CvodeThreadData& z = ctd_[_nt->id]; // how many ode's are there? First ones are non-zero capacitance // nodes with non-zero capacitance zneq_cap_v = z.cmlcap_ ? z.cmlcap_->ml->nodecount : 0; zneq = zneq_cap_v; // now add the membrane mechanism ode's to the count for (cml = z.cv_memb_list_; cml; cml = cml->next) { Pfridot s = (Pfridot)memb_func[cml->index].ode_count; if (s) { zneq += cml->ml->nodecount * (*s)(cml->index); } } //printf("%d Cvode::init_eqn neq_v=%d zneq_=%d\n", nrnmpi_myid, neq_v, zneq_); if (z.pv_) { delete [] z.pv_; delete [] z.pvdot_; z.pv_ = 0; z.pvdot_ = 0; } if (zneq) { z.pv_ = new double*[zneq]; z.pvdot_ = new double*[zneq]; } z.nvoffset_ = neq_; z.nvsize_ = zneq; neq_ += zneq; if (nth_) { break; } //lvardt } #if PARANEURON if (use_partrans_) { global_neq_ = nrnmpi_int_sum_reduce(neq_, mpicomm_); //printf("%d global_neq_=%d neq=%d\n", nrnmpi_myid, global_neq_, neq_); } #endif atolvec_alloc(neq_); for (int id = 0; id < nctd_; ++id) { CvodeThreadData& z = ctd_[id]; double* atv = n_vector_data(atolnvec_, id); zneq_cap_v = z.cmlcap_ ? z.cmlcap_->ml->nodecount : 0; zneq = z.nvsize_; zneq_v = zneq_cap_v; for (i=0; i < zneq; ++i) { atv[i] = ncv_->atol(); } vtol = 1.; if (!vsym) { vsym = hoc_table_lookup("v", hoc_built_in_symlist); } if (vsym->extra) { double x; x = vsym->extra->tolerance; if (x != 0 && x < vtol) { vtol = x; } } for (i=0; i < zneq_cap_v; ++i) { atv[i] *= vtol; } // deal with voltage nodes // only cap nodes for cvode for (i=0; i < z.v_node_count_; ++i) { //sentinal values for determining no_cap NODERHS(z.v_node_[i]) = 1.; } for (i=0; i < zneq_cap_v; ++i) { ml = z.cmlcap_->ml; z.pv_[i] = &NODEV(ml->nodelist[i]); z.pvdot_[i] = &(NODERHS(ml->nodelist[i])); *z.pvdot_[i] = 0.; // only ones = 1 are no_cap } // the remainder are no_cap nodes if (z.no_cap_node_) { delete [] z.no_cap_node_; delete [] z.no_cap_child_; } z.no_cap_node_ = new Node*[z.v_node_count_ - zneq_cap_v]; z.no_cap_child_ = new Node*[z.v_node_count_ - zneq_cap_v]; z.no_cap_count_ = 0; j = 0; for (i=0; i < z.v_node_count_; ++i) { if (NODERHS(z.v_node_[i]) > .5) { z.no_cap_node_[z.no_cap_count_++] = z.v_node_[i]; } if (z.v_parent_[i] && NODERHS(z.v_parent_[i]) > .5) { z.no_cap_child_[j++] = z.v_node_[i]; } } z.no_cap_child_count_ = j; // use the sentinal values in NODERHS to construct a new no cap membrane list new_no_cap_memb(z, _nt); // map the membrane mechanism ode state and dstate pointers int ieq = zneq_v; for (cml = z.cv_memb_list_; cml; cml = cml->next) { int n; ml = cml->ml; mf = memb_func + cml->index; Pfridot sc = (Pfridot)mf->ode_count; if (sc && ( (n = (*sc)(cml->index)) > 0)) { Pfridot s = (Pfridot)mf->ode_map; if (mf->hoc_mech) { for (j=0; j < ml->nodecount; ++j) { (*s)(ieq, z.pv_ + ieq, z.pvdot_ + ieq, ml->prop[j], atv + ieq); ieq += n; } }else{ for (j=0; j < ml->nodecount; ++j) { (*s)(ieq, z.pv_ + ieq, z.pvdot_ + ieq, ml->data[j], ml->pdata[j], atv + ieq, cml->index); ieq += n; } } } } } structure_change_ = false; }