void Cvode::nocap_v_part1(NrnThread* _nt){ int i; CvodeThreadData& z = ctd_[_nt->id]; for (i = 0; i < z.no_cap_count_; ++i) { // initialize storage Node* nd = z.no_cap_node_[i]; NODED(nd) = 0; NODERHS(nd) = 0; } // compute the i(vmold) and di/dv rhs_memb(z.no_cap_memb_, _nt); lhs_memb(z.no_cap_memb_, _nt); for (i = 0; i < z.no_cap_count_; ++i) {// parent axial current Node* nd = z.no_cap_node_[i]; // following from global v_parent NODERHS(nd) += NODED(nd) * NODEV(nd); Node* pnd = _nt->_v_parent[nd->v_node_index]; if (pnd) { NODERHS(nd) -= NODEB(nd) * NODEV(pnd); NODED(nd) -= NODEB(nd); } } for (i = 0; i < z.no_cap_child_count_; ++i) {// child axial current Node* nd = z.no_cap_child_[i]; // following from global v_parent Node* pnd = _nt->_v_parent[nd->v_node_index]; NODERHS(pnd) -= NODEA(nd) * NODEV(nd); NODED(pnd) -= NODEA(nd); } nrn_multisplit_nocap_v_part1(_nt); }
method3_axial_current() { int i; #if _CRAY #pragma _CRI ivdep #endif for (i=rootnodecount; i < v_node_count; ++ i) { Node* nd = v_node[i]; Node* pnd = v_parent[i]; nd->toparent.current += nd->toparent.djdv0 * nd->v + NODEB(nd) * pnd->v; nd->fromparent.current += nd->fromparent.djdv0 * pnd->v + NODEA(nd) * nd->v; } #if 0 printf("cur0 %g curleft %g curright %g\n", v_node[rootnodecount]->fromparent.current, v_node[rootnodecount]->toparent.current, v_node[rootnodecount+1]->fromparent.current ); #endif }
void Cvode::nocap_v(NrnThread* _nt){ int i; CvodeThreadData& z = CTD(_nt->id); for (i = 0; i < z.no_cap_count_; ++i) { // initialize storage Node* nd = z.no_cap_node_[i]; NODED(nd) = 0; NODERHS(nd) = 0; } // compute the i(vmold) and di/dv rhs_memb(z.no_cap_memb_, _nt); lhs_memb(z.no_cap_memb_, _nt); for (i = 0; i < z.no_cap_count_; ++i) {// parent axial current Node* nd = z.no_cap_node_[i]; // following from global v_parent NODERHS(nd) += NODED(nd) * NODEV(nd); Node* pnd = _nt->_v_parent[nd->v_node_index]; if (pnd) { NODERHS(nd) -= NODEB(nd) * NODEV(pnd); NODED(nd) -= NODEB(nd); } } for (i = 0; i < z.no_cap_child_count_; ++i) {// child axial current Node* nd = z.no_cap_child_[i]; // following from global v_parent Node* pnd = _nt->_v_parent[nd->v_node_index]; NODERHS(pnd) -= NODEA(nd) * NODEV(nd); NODED(pnd) -= NODEA(nd); } #if PARANEURON if (nrn_multisplit_solve_) { // add up the multisplit equations nrn_multisplit_nocap_v(); } #endif for (i = 0; i < z.no_cap_count_; ++i) { Node* nd = z.no_cap_node_[i]; NODEV(nd) = NODERHS(nd) / NODED(nd); // printf("%d %d %g v=%g\n", nrnmpi_myid, i, _nt->_t, NODEV(nd)); } // no_cap v's are now consistent with adjacent v's }
/* triangularization of the matrix equations */ void Cvode::triang(NrnThread* _nt) { register 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); } }
fmatrix() { if (ifarg(1)) { extern Node* node_exact(Section*, double); double x = chkarg(1, 0., 1.); int id = (int)chkarg(2, 1., 4.); Node* nd = node_exact(chk_access(), x); NrnThread* _nt = nd->_nt; switch (id) { case 1: ret(NODEA(nd)); break; case 2: ret(NODED(nd)); break; case 3: ret(NODEB(nd)); break; case 4: ret(NODERHS(nd)); break; } return; } nrn_print_matrix(nrn_threads); ret(1.); }
void Cvode::rhs(NrnThread* _nt) { int i; CvodeThreadData& z = CTD(_nt->id); if (diam_changed) { recalc_diam(); } if (z.v_node_count_ == 0) { return; } for (i = 0; i < z.v_node_count_; ++i) { NODERHS(z.v_node_[i]) = 0.; } if (_nt->_nrn_fast_imem) { double* p = _nt->_nrn_fast_imem->_nrn_sav_rhs; for (i = 0; i < z.v_node_count_; ++i) { Node* nd = z.v_node_[i]; p[nd->v_node_index] = 0; } } rhs_memb(z.cv_memb_list_, _nt); nrn_nonvint_block_current(_nt->end, _nt->_actual_rhs, _nt->id); if (_nt->_nrn_fast_imem) { double* p = _nt->_nrn_fast_imem->_nrn_sav_rhs; for (i = 0; i < z.v_node_count_; ++i) { Node* nd = z.v_node_[i]; p[nd->v_node_index] -= NODERHS(nd); } } /* at this point d contains all the membrane conductances */ /* now the internal axial currents. rhs += ai_j*(vi_j - vi) */ for (i = z.rootnodecount_; i < z.v_node_count_; ++i) { Node* nd = z.v_node_[i]; Node* pnd = z.v_parent_[i]; double dv = NODEV(pnd) - NODEV(nd); /* our connection coefficients are negative so */ NODERHS(nd) -= NODEB(nd)*dv; NODERHS(pnd) += NODEA(nd)*dv; } }
void Cvode::lhs(NrnThread* _nt) { int i; CvodeThreadData& z = CTD(_nt->id); if (z.v_node_count_ == 0) { return; } for (i = 0; i < z.v_node_count_; ++i) { NODED(z.v_node_[i]) = 0.; } lhs_memb(z.cv_memb_list_, _nt); nrn_nonvint_block_conductance(_nt->end, _nt->_actual_rhs, _nt->id); nrn_cap_jacob(_nt, z.cmlcap_->ml); // _nrn_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]); } }
void NonLinImpRep::didv() { int i, j, ip; Node* nd; NrnThread* _nt = nrn_threads; // d2v/dv2 terms for (i=_nt->ncell; i < n_v_; ++i) { nd = _nt->_v_node[i]; ip = _nt->_v_parent[i]->v_node_index; double* a = cmplx_spGetElement(m_, v_index_[ip], v_index_[i]); double* b = cmplx_spGetElement(m_, v_index_[i], v_index_[ip]); *a += NODEA(nd); *b += NODEB(nd); *diag_[i] -= NODEB(nd); *diag_[ip] -= NODEA(nd); } // jwC term Memb_list* mlc = _nt->tml->ml; int n = mlc->nodecount; for (i=0; i < n; ++i) { double* cd = mlc->data[i]; j = mlc->nodelist[i]->v_node_index; diag_[v_index_[j]-1][1] += .001 * cd[0] * omega_; } // di/dv terms // because there may be several point processes of the same type // at the same location, we have to be careful to neither increment that // nd->v multiple times nor count the rhs multiple times. // So we can't take advantage of vectorized point processes. // To avoid this we do each mechanism item separately. // We assume there is no interaction between // separate locations. Note that interactions such as gap junctions // would not be handled in any case without computing a full jacobian. // i.e. calling nrn_rhs varying every state one at a time (that would // give the d2v/dv2 terms as well), but the expense is unwarranted. for (NrnThreadMembList* tml = _nt->tml; tml; tml = tml->next) { i = tml->index; if (i == CAP) { continue; } if (!memb_func[i].current) { continue; } Memb_list* ml = tml->ml; double* x1 = rv_; // use as temporary storage double* x2 = jv_; for (j = 0; j < ml->nodecount; ++j) { Node* nd = ml->nodelist[j]; // zero rhs // save v NODERHS(nd) = 0; x1[j] = NODEV(nd); // v+dv NODEV(nd) += delta_; current(i, ml, j); // save rhs // zero rhs // restore v x2[j] = NODERHS(nd); NODERHS(nd) = 0; NODEV(nd) = x1[j]; current(i, ml, j); // conductance // add to matrix *diag_[v_index_[nd->v_node_index]-1] -= (x2[j] - NODERHS(nd))/delta_; } } }
method3_setup_tree_matrix() /* construct diagonal elements */ { int i; if (diam_changed) { recalc_diam(); } #if _CRAY #pragma _CRI ivdep #endif for (i = 0; i < v_node_count; ++i) { Node* nd = v_node[i]; NODED(nd) = 0.; NODERHS(nd) = 0.; nd->thisnode.GC = 0.; nd->thisnode.EC = 0.; } for (i=0; i < n_memb_func; ++i) if (memb_func[i].current && memb_list[i].nodecount) { if (memb_func[i].vectorized) { memb_func[i].current( memb_list[i].nodecount, memb_list[i].nodelist, memb_list[i].data, memb_list[i].pdata ); }else{ int j, count; Pfrd s = memb_func[i].current; Memb_list* m = memb_list + i; count = m->nodecount; if (memb_func[i].is_point) { for (j = 0; j < count; ++j) { Node* nd = m->nodelist[j]; NODERHS(nd) -= (*s)(m->data[j], m->pdata[j], &NODED(nd),nd->v); }; }else{ for (j = 0; j < count; ++j) { Node* nd = m->nodelist[j]; nd->thisnode.EC -= (*s)(m->data[j], m->pdata[j], &nd->thisnode.GC,nd->v); }; } } if (errno) { if (nrn_errno_check(i)) { hoc_warning("errno set during calculation of currents", (char*)0); } } } #if 0 && _CRAY #pragma _CRI ivdep #endif for (i=rootnodecount; i < v_node_count; ++i) { Node* nd2; Node* nd = v_node[i]; Node* pnd = v_parent[nd->v_node_index]; double dg, de, dgp, dep, fac; #if 0 if (i == rootnodecount) { printf("v0 %g vn %g jstim %g jleft %g jright %g\n", nd->v, pnd->v, nd->fromparent.current, nd->toparent.current, nd[1].fromparent.current); } #endif /* dg and de must be second order when used */ if ((nd2 = nd->toparent.nd2) != (Node*)0) { dgp = -(3*(pnd->thisnode.GC - pnd->thisnode.Cdt) - 4*(nd->thisnode.GC - nd->thisnode.Cdt) +(nd2->thisnode.GC - nd2->thisnode.Cdt))/2 ; dep = -(3*(pnd->thisnode.EC - pnd->thisnode.Cdt * pnd->v) - 4*(nd->thisnode.EC - nd->thisnode.Cdt * nd->v) +(nd2->thisnode.EC - nd2->thisnode.Cdt * nd2->v))/2 ; }else{ dgp = 0.; dep = 0.; } if ((nd2 = pnd->fromparent.nd2) != (Node*)0) { dg = -(3*(nd->thisnode.GC - nd->thisnode.Cdt) - 4*(pnd->thisnode.GC - pnd->thisnode.Cdt) +(nd2->thisnode.GC - nd2->thisnode.Cdt))/2 ; de = -(3*(nd->thisnode.EC - nd->thisnode.Cdt * nd->v) - 4*(pnd->thisnode.EC - pnd->thisnode.Cdt * pnd->v) +(nd2->thisnode.EC - nd2->thisnode.Cdt * nd2->v))/2 ; }else{ dg = 0.; de = 0.; } fac = 1. + nd->toparent.coefjdot * nd->thisnode.GC; nd->toparent.djdv0 = ( nd->toparent.coefj + nd->toparent.coef0 * nd->thisnode.GC + nd->toparent.coefdg * dg )/fac; NODED(nd) += nd->toparent.djdv0; nd->toparent.current = ( - nd->toparent.coef0 * nd->thisnode.EC - nd->toparent.coefn * pnd->thisnode.EC + nd->toparent.coefjdot * nd->thisnode.Cdt * nd->toparent.current - nd->toparent.coefdg * de )/fac; NODERHS(nd) -= nd->toparent.current; NODEB(nd) = ( - nd->toparent.coefj + nd->toparent.coefn * pnd->thisnode.GC )/fac; /* this can break cray vectors */ fac = 1. + nd->fromparent.coefjdot * pnd->thisnode.GC; nd->fromparent.djdv0 = ( nd->fromparent.coefj + nd->fromparent.coef0 * pnd->thisnode.GC + nd->fromparent.coefdg * dgp )/fac; pNODED(nd) += nd->fromparent.djdv0; nd->fromparent.current = ( - nd->fromparent.coef0 * pnd->thisnode.EC - nd->fromparent.coefn * nd->thisnode.EC + nd->fromparent.coefjdot * nd->thisnode.Cdt * nd->fromparent.current - nd->fromparent.coefdg * dep )/fac; pNODERHS(nd) -= nd->fromparent.current; NODEA(nd) = ( - nd->fromparent.coefj + nd->fromparent.coefn * nd->thisnode.GC )/fac; } activstim(); activsynapse(); #if SEJNOWSKI activconnect(); #endif activclamp(); }