Exemple #1
0
int NonLinImpRep::gapsolve() {
  // On entry, rv_ and jv_ contain the complex b for A*x = b.
  // On return rv_ and jv_ contain complex solution, x.
  // m_ is the factored matrix for the trees without gap junctions
  // Jacobi method (easy for parallel)
  // A = D + R
  // D*x_(k+1) = (b - R*x_(k))
  // D is m_ (and includes the gap junction contribution to the diagonal)
  // R is the off diagonal matrix of the gaps.

  // one and only one stimulus
#if NRNMPI
  if (nrnmpi_numprocs > 1 && nrnmpi_int_sum_reduce(iloc_ >= 0 ? 1 : 0) != 1) {
    if (nrnmpi_myid == 0) {
      hoc_execerror("there can be one and only one impedance stimulus", 0);
    }
  }
#endif

  double *rx, *jx, *rx1, *jx1, *rb, *jb;
  if (neq_) {
    rx = new double[neq_];
    jx = new double[neq_];
    rx1 = new double[neq_];
    jx1 = new double[neq_];
    rb = new double[neq_];
    jb = new double[neq_];
  }

  // initialize for first iteration
  for (int i=0; i < neq_; ++i) {
    rx[i] = jx[i] = 0.0;
    rb[i] = rv_[i];
    jb[i] = jv_[i];
  }

  pargap_jacobi_setup(0);

  // iterate till change in x is small
  double tol = 1e-9;
  double delta;
  
  int success = 0;
  int iter;

  for (iter = 1; iter <= maxiter_; ++iter) {
    if (neq_) {
      cmplx_spSolve(m_, rb-1, rx1-1, jb-1, jx1-1);
    }
    
    // if any change in x > tol, then do another iteration.
    success = 1;
    delta = 0.0;
    for (int i=0; i < neq_; ++i) {
      double err = fabs(rx1[i] - rx[i]) + fabs(jx1[i] - jx[i]);
      if (err > tol) {
        success = 0;
      }
      if (delta < err) {
        delta = err;
      }
    }
#if NRNMPI
    if (nrnmpi_numprocs > 1) {
      success = nrnmpi_int_sum_reduce(success) / nrnmpi_numprocs;
    }
#endif
    if (success) {
      for (int i=0; i < neq_; ++i) {
        rv_[i] = rx1[i];
        jv_[i] = jx1[i];
      }
      break;
    }

    // setup for next iteration
    for (int i=0; i < neq_; ++i) {
      rx[i] = rx1[i];
      jx[i] = jx1[i];
      rb[i] = rv_[i];
      jb[i] = jv_[i];
    }
    pargap_jacobi_rhs(rb, rx);
    pargap_jacobi_rhs(jb, jx);
  }

  pargap_jacobi_setup(1); // tear down

  if (neq_) {
    delete [] rx;
    delete [] jx;
    delete [] rx1;
    delete [] jx1;
    delete [] rb;
    delete [] jb;
  }

  if (!success) {
    char buf[256];
    sprintf(buf, "Impedance calculation did not converge in %d iterations. Max state change on last iteration was %g (Iterations stop at %g)\n",
      maxiter_, delta, tol);
    execerror(buf, 0);
  }
  return iter;
}
Exemple #2
0
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;
}