1 #include <../../nrnconf.h>
11 #include <Eigen/Sparse>
14 using namespace std::complex_literals;
22 const std::vector<std::complex<double>>&);
39 Eigen::SparseMatrix<std::complex<double>> m_{};
41 Eigen::SparseLU<Eigen::SparseMatrix<std::complex<double>>> lu_{};
43 int n_v_,
n_ext_, n_lin_, n_ode_, neq_v_, neq_;
44 std::vector<neuron::container::data_handle<double>>
pv_, pvdot_;
45 std::vector<std::complex<double>>
v_;
64 "current injection site change not allowed with both gap junctions and nhost > 1", 0);
66 if (curloc != rep_->iloc_) {
69 return std::abs(rep_->v_[vloc]);
73 hoc_execerror(
"not allowed with both gap junctions and nhost>1", 0);
75 if (curloc != rep_->iloc_) {
81 return std::abs(rep_->v_[curloc]);
86 "current injection site change not allowed with both gap junctions and nhost > 1", 0);
88 if (curloc != rep_->iloc_) {
91 return std::arg(rep_->v_[vloc]);
95 hoc_execerror(
"not allowed with both gap junctions and nhost>1", 0);
97 if (curloc != rep_->iloc_) {
103 return std::arg(rep_->v_[curloc]);
107 hoc_execerror(
"not allowed with both gap junctions and nhost>1", 0);
112 if (clmploc != rep_->iloc_) {
115 return std::abs(rep_->v_[vloc] * std::conj(rep_->v_[clmploc]) /
std::norm(rep_->v_[clmploc]));
127 rep_->maxiter_ = maxiter;
128 if (rep_->neq_ == 0) {
132 hoc_execerror(
"Impedance calculation with LinearMechanism not implemented", 0);
135 hoc_execerror(
"Impedance calculation with extracellular not implemented", 0);
138 rep_->omega_ = 1000. * omega;
152 rep_->m_.makeCompressed();
155 rep_->lu_.compute(rep_->m_);
156 switch (rep_->lu_.info()) {
160 case Eigen::NumericalIssue:
162 "Eigen Sparse LU factorization failed with Eigen::NumericalIssue, please check the "
164 rep_->lu_.lastErrorMessage().c_str());
166 case Eigen::NoConvergence:
168 "Eigen Sparse LU factorization reports Eigen::NonConvergence after calling compute():",
169 rep_->lu_.lastErrorMessage().c_str());
171 case Eigen::InvalidInput:
173 "Eigen Sparse LU factorization failed with Eigen::InvalidInput, the input matrix seems "
175 rep_->lu_.lastErrorMessage().c_str());
188 if (rep_->iloc_ != curloc) {
189 rep_->iloc_ = curloc;
190 rep_->v_ = std::vector<std::complex<double>>(rep_->neq_);
195 rval = rep_->gapsolve();
198 Eigen::Map<Eigen::Vector<std::complex<double>, Eigen::Dynamic>>(rep_->v_.data(),
200 v = rep_->lu_.solve(
v);
238 neq_v_ = n_v_ + n_ext_ + n_lin_;
239 neq_ = neq_v_ + n_ode_;
243 m_.resize(neq_, neq_);
247 deltavec_.resize(neq_);
249 for (
int i = 0;
i < n_v_; ++
i) {
261 for (
i = 0;
i < neq_; ++
i) {
271 for (
auto j = 0;
j < nc; ++
j) {
276 deltavec_.data() + ieq,
282 delta_ = (vsymtol_ && (*vsymtol_ != 0.)) ? *vsymtol_ : 1.;
291 for (
i = _nt->
ncell;
i < n_v_; ++
i) {
294 m_.coeffRef(ip,
i) +=
NODEA(nd);
295 m_.coeffRef(
i, ip) +=
NODEB(nd);
296 m_.coeffRef(
i,
i) -=
NODEB(nd);
297 m_.coeffRef(ip, ip) -=
NODEA(nd);
302 for (
i = 0;
i <
n; ++
i) {
304 m_.coeffRef(
j,
j) += .001 * mlc->
data(
i, 0) * omega_ * 1
i;
332 double x1 =
NODEV(nd);
334 nd->
v() = x1 + delta_;
354 int ieq,
i, in, is, iis;
374 for (iis = 0; iis <
cnt; ++iis) {
375 is = ieq + in *
cnt + iis;
377 v_[is].real(*pv_[is]);
379 *pv_[is] += deltavec_[is];
382 *pv_[is] = v_[is].real();
383 double g = (
NODERHS(nd) - v_[in].imag()) / deltavec_[is];
399 int ieq,
i, in, is, iis;
413 for (is = ieq + in *
cnt, iis = 0; iis <
cnt; ++iis, ++is) {
416 v_[in].real(
NODEV(nd));
422 auto const v = nd->
v();
423 if (v_[in].real() ==
v) {
424 nd->
v() =
v + delta_;
432 for (is = ieq + in *
cnt, iis = 0; iis <
cnt; ++iis, ++is) {
433 v_[is].imag(*pvdot_[is]);
436 nd->
v() = v_[in].real();
443 for (is = ieq + in *
cnt, iis = 0; iis <
cnt; ++iis, ++is) {
444 double ds = (v_[is].imag() - *pvdot_[is]) / delta_;
457 int ieq,
i, in, is, iis, ks, kks;
460 for (
i = neq_v_;
i < neq_; ++
i) {
461 m_.coeffRef(
i,
i) += omega_ * 1
i;
473 for (is = ieq + in *
cnt, iis = 0; iis <
cnt; ++iis, ++is) {
475 v_[is].real(*pv_[is]);
482 for (is = ieq + in *
cnt, iis = 0; iis <
cnt; ++iis, ++is) {
483 v_[is].imag(*pvdot_[is]);
487 for (kks = 0; kks <
cnt; ++kks) {
490 ks = ieq + in *
cnt + kks;
491 for (is = ieq + in *
cnt, iis = 0; iis <
cnt; ++iis, ++is) {
494 *pv_[ks] += deltavec_[ks];
501 ks = ieq + in *
cnt + kks;
502 for (is = ieq + in *
cnt, iis = 0; iis <
cnt; ++iis, ++is) {
503 double ds = (*pvdot_[is] - v_[is].imag()) / deltavec_[is];
505 m_.coeffRef(is, ks) = -ds;
507 *pv_[ks] = v_[ks].real();
526 mfake.pdata = ml->
pdata + in;
527 mfake.prop = ml->
prop ? ml->
prop + in :
nullptr;
551 if (
nrnmpi_numprocs > 1 && nrnmpi_int_sum_reduce(iloc_ >= 0 ? 1 : 0) != 1) {
553 hoc_execerror(
"there can be one and only one impedance stimulus", 0);
560 std::vector<std::complex<double>> x_old(neq_);
561 std::vector<std::complex<double>> x(neq_);
562 std::vector<std::complex<double>> b(v_);
571 for (iter = 1; iter <= maxiter_; ++iter) {
573 auto b_ = Eigen::Map<Eigen::Vector<std::complex<double>, Eigen::Dynamic>>(b.data(),
575 auto x_ = Eigen::Map<Eigen::Vector<std::complex<double>, Eigen::Dynamic>>(x.data(),
585 for (
int i = 0;
i < neq_; ++
i) {
586 auto diff = x[
i] - x_old[
i];
587 double err = std::abs(diff.real()) + std::abs(diff.imag());
591 delta = std::max(err, delta);
614 "Impedance calculation did not converge in %d iterations. Max state change on last "
615 "iteration was %g (Iterations stop at %g)\n",
double transfer_amp(int curloc, int vloc)
void compute(double omega, double deltafac, int maxiter)
double ratio_amp(int clmploc, int vloc)
double input_phase(int curloc)
double input_amp(int curloc)
double transfer_phase(int curloc, int vloc)
std::vector< neuron::container::data_handle< double > > pv_
std::vector< double > deltavec_
std::vector< std::complex< double > > v_
void ode(int, Memb_list *)
void current(int, Memb_list *, int)
Symbol * hoc_table_lookup(const char *, Symlist *)
static double solve(void *v)
static double deltafac(void *v)
static int ode_count(int type)
static void ode_map(Prop *prop, int ieq, neuron::container::data_handle< double > *pv, neuron::container::data_handle< double > *pvdot, double *atol, int type)
void(*)(Prop *, int, neuron::container::data_handle< double > *, neuron::container::data_handle< double > *, double *, int) nrn_ode_map_t
int(* nrn_ode_count_t)(int)
double norm(const Point3D &p1)
void hoc_execerror(const char *s1, const char *s2)
static void nrn_rhs(NrnThread *_nt)
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
void(* nrnthread_v_transfer_)(NrnThread *)
void pargap_jacobi_setup(int mode)
void pargap_jacobi_rhs(std::vector< std::complex< double >> &, const std::vector< std::complex< double >> &)
int nrndae_extra_eqn_count()
Symlist * hoc_built_in_symlist
neuron::model_sorted_token nrn_ensure_model_data_are_sorted()
Ensure neuron::container::* data are sorted.
int const size_t const size_t n
std::vector< Memb_func > memb_func
A view into a set of mechanism instances.
std::vector< double * > data()
Get a vector of double* representing the model data.
std::size_t get_storage_offset() const
Get the offset of this Memb_list into global storage for this type.
Represent main neuron object computed by single thread.
Memb_list * _ecell_memb_list
struct NrnThreadMembList * next
Memb_list * _ecell_memb_list