NEURON
nrndae.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include <cstdio>
3 #include "nrndae.h"
4 #include "nrndae_c.h"
5 #include "nrnoc2iv.h"
6 #include "treeset.h"
7 #include "utils/enumerate.h"
8 
9 extern int secondorder;
10 
12 
14  return nrndae_list.empty() ? 1 : 0;
15 }
16 
17 
19  nrndae_list.push_back(n);
20 }
21 
23  nrndae_list.remove(n);
24 }
25 
27  int neqn = 0;
28  for (NrnDAE* item: nrndae_list) {
29  neqn += item->extra_eqn_count();
30  }
31  return neqn;
32 }
33 
36  for (NrnDAE* item: nrndae_list) {
37  item->update();
38  }
40 }
41 
42 void nrndae_alloc() {
43  NrnThread* _nt = nrn_threads;
44  nrn_thread_error("NrnDAE only one thread allowed");
45  int neqn = _nt->end;
46  if (_nt->_ecell_memb_list) {
48  }
49  for (NrnDAE* item: nrndae_list) {
50  item->alloc(neqn + 1);
51  neqn += item->extra_eqn_count();
52  }
53 }
54 
55 
56 void nrndae_init() {
57  for (int it = 0; it < nrn_nthread; ++it) {
58  auto* const nt = std::next(nrn_threads, it);
61  }
62  if ((!nrndae_list.empty()) &&
63  (secondorder > 0 || ((cvode_active_ > 0) && (nrn_use_daspk_ == 0)))) {
64  hoc_execerror("NrnDAEs only work with secondorder==0 or daspk", 0);
65  }
66  for (NrnDAE* item: nrndae_list) {
67  item->init();
68  }
69  for (int it = 0; it < nrn_nthread; ++it) {
70  auto* const nt = std::next(nrn_threads, it);
73  }
74 }
75 
76 void nrndae_rhs(NrnThread* _nt) {
79  for (NrnDAE* item: nrndae_list) {
80  item->rhs();
81  }
84 }
85 
86 void nrndae_lhs() {
87  for (NrnDAE* item: nrndae_list) {
88  item->lhs();
89  }
90 }
91 
92 void nrndae_dkmap(std::vector<double*>& pv, std::vector<double*>& pvdot) {
93  for (NrnDAE* item: nrndae_list) {
94  item->dkmap(pv, pvdot);
95  }
96 }
97 
98 void nrndae_dkres(double* y, double* yprime, double* delta) {
99  // c*y' = f(y) so
100  // delta = c*y' - f(y)
101  for (NrnDAE* item: nrndae_list) {
102  item->dkres(y, yprime, delta);
103  }
104 }
105 
106 inline void NrnDAE::alloc_(int size, int start, int nnode, Node** nodes, int* elayer) {}
107 
108 void NrnDAE::alloc(int start_index) {
109  // printf("NrnDAE::alloc %lx\n", (long)this);
110  size_ = y_.size();
111  if (y0_) {
112  assert(y0_->size() == size_);
113  }
114  assert(c_->nrow() == size_ && c_->ncol() == size_);
115  cyp_.resize(size_);
117  start_ = start_index;
118  // printf("start=%d size=%d\n", start_, size_);
119  delete[] bmap_;
120  bmap_ = new int[size_];
121  for (int i = 0; i < size_; ++i) {
122  if (i < nnode_) {
123  bmap_[i] = nodes_[i]->eqn_index_ + elayer_[i];
124  if (elayer_[i] > 0 && !nodes_[i]->extnode) {
125  // hoc_execerror(secname(nodes_[i]->sec), "NrnDAE: Referring to an extracellular
126  // layer but\nextracellular is not inserted.");
127  // instead treat as though connected to ground.
128  bmap_[i] = 0;
129  }
130  } else {
131  bmap_[i] = start_ + i - nnode_;
132  }
133  }
134  // printf("c_->alloc start=%d, nnode=%d\n", start_, nnode_);
136 
137  // allow subclasses to do their own allocations as well
139 }
140 
142  Vect* const yvec,
143  Vect* const y0,
144  int nnode,
145  Node** const nodes,
146  Vect* const elayer,
147  void (*f_init)(void* data),
148  void* const data)
149  : y_(*yvec)
150  , yptmp_((Object*) NULL)
151  , cyp_((Object*) NULL)
152  , f_init_(f_init)
153  , data_(data) {
154  // printf("NrnDAE %lx\n", (long)this);
155  if (cmat) {
157  } else {
158  const int size = y_.size();
159  assumed_identity_ = new OcSparseMatrix(size, size);
160  // assumed_identity_->setdiag(0, 1);
161  for (int i = 0; i < size; i++)
162  (*assumed_identity_)(i, i) = 1;
163  cmat = assumed_identity_;
164  }
165  c_ = new MatrixMap(cmat);
166  Vect& elay = *elayer;
167  nnode_ = nnode;
168  nodes_ = nodes;
169  if (nnode_ > 0) {
170  elayer_ = new int[nnode_];
171  if (elayer) {
172  for (int i = 0; i < nnode_; ++i) {
173  elayer_[i] = int(elay[i]);
174  }
175  } else {
176  for (int i = 0; i < nnode_; ++i) {
177  elayer_[i] = 0;
178  }
179  }
180  } else {
181  elayer_ = NULL;
182  }
183  y0_ = y0;
184  bmap_ = new int[1];
185 
186  nrndae_register(this);
187  // use_sparse13 = 1;
189 }
190 
191 
193  nrndae_deregister(this);
194  delete[] bmap_;
195  delete c_;
196  delete assumed_identity_;
197  if (elayer_) {
198  delete[] elayer_;
199  }
200  // if (nrndae_list->count() == 0) {
201  // use_sparse13 = 0;
202  // }
204 }
205 
206 
208  // printf("NrnDAE::extra_eqn_count %lx\n", (long)this);
209  // printf(" nnode_=%d g_->nrow()=%d\n", nnode_, g_->nrow());
210  return c_->nrow() - nnode_;
211 }
212 
213 // Switch back from data_handle to double*
214 void NrnDAE::dkmap(std::vector<double*>& pv, std::vector<double*>& pvdot) {
215  // printf("NrnDAE::dkmap\n");
216  NrnThread* _nt = nrn_threads;
217  for (int i = nnode_; i < size_; ++i) {
218  // printf("bmap_[%d] = %d\n", i, bmap_[i]);
219  pv[bmap_[i] - 1] = y_.data() + i;
220  pvdot[bmap_[i] - 1] = _nt->_sp13_rhs + bmap_[i];
221  }
222 }
223 
225  // printf("NrnDAE::update %lx\n", (long)this);
226  NrnThread* _nt = nrn_threads;
227  // note that the following is correct also for states that refer
228  // to the internal potential of a segment. i.e rhs is v + vext[0]
229  for (int i = 0; i < size_; ++i) {
230  y_[i] += _nt->_sp13_rhs[bmap_[i]];
231  }
232  // for (int i=0; i < size_; ++i) printf(" i=%d bmap_[i]=%d y_[i]=%g\n", i, bmap_[i],
233  // y_->elem(i));
234 }
235 
236 void NrnDAE::init() {
237  // printf("NrnDAE::init %lx\n", (long)this);
238  // printf("init size_=%d %d %d %d\n", size_, y_->size(), y0_->size(), b_->size());
239  Vect& y0 = *y0_;
240 
241  v2y();
242  if (f_init_) {
243  f_init_(data_);
244  } else {
245  if (y0_) {
246  for (int i = nnode_; i < size_; ++i) {
247  y_[i] = y0[i];
248  }
249  } else {
250  for (int i = nnode_; i < size_; ++i) {
251  y_[i] = 0.;
252  }
253  }
254  }
255  // for (i=0; i < nnode_; ++i) printf(" i=%d y[i]=%g\n", i, y[i]);
256 }
257 
258 void NrnDAE::v2y() {
259  // vm,vext may be reinitialized between fixed steps and certainly
260  // have been adjusted by daspk
261 
262  for (int i = 0; i < nnode_; ++i) {
263  Node* nd = nodes_[i];
264  // Note elayer_[0] refers to internal.
265  if (elayer_[i] == 0) {
266  y_[i] = NODEV(nd);
267  if (nd->extnode) {
268  y_[i] += nd->extnode->v[0];
269  }
270  } else if (nd->extnode) {
271  y_[i] = nd->extnode->v[elayer_[i] - 1];
272  }
273  }
274 }
275 
276 
277 void NrnDAE::dkres(double* y, double* yprime, double* delta) {
278  // printf("NrnDAE::dkres %lx\n", (long)this);
279  // delta is already f(y)
280  // now subtract c*y'
281  // The problem is the map between y and yprime and the local
282  // representation of the y and yprime
283 
284  for (int i = 0; i < size_; ++i) {
285  // printf("%d %d %g %g\n", i, bmap_[i]-1, y[bmap_[i]-1], yprime[bmap_[i]-1]);
286  yptmp_[i] = yprime[bmap_[i] - 1];
287  }
288  Vect* cyp;
289  if (assumed_identity_) {
290  // if c_ is KNOWN to be the identity matrix, then no multiplication to do
291  // for now, this happens only when cmat = NULL
292  // note that the user might change cmat, so we can't assume that if it's initially
293  // the identity that it will stay that way
294  cyp = &yptmp_;
295  } else {
296  c_->mulv(yptmp_, cyp_); // mulv cannot multiply in place
297  cyp = &cyp_;
298  }
299  for (int i = 0; i < size_; ++i) {
300  delta[bmap_[i] - 1] -= (*cyp)[i];
301  }
302 }
303 
304 
305 void NrnDAE::rhs() {
306  NrnThread* _nt = nrn_threads;
307  v2y();
308  f_(y_, yptmp_, size_);
309  for (int i = 0; i < size_; ++i) {
310  _nt->_sp13_rhs[bmap_[i]] += yptmp_[i];
311  }
312 }
313 
314 void NrnDAE::lhs() {
315  // printf("NrnDAE::lhs %lx\n", (long)this);
316  // printf(" nrn_threads[0].cj = %g\n", nrn_threads[0].cj);
317  // left side portion of (c/dt - J)*[dy] = f(y)
318  c_->add(nrn_threads[0].cj);
319  v2y();
321 }
double const * data() const
Definition: ivocvect.h:34
size_t size() const
Definition: ivocvect.h:42
void resize(size_t n)
Definition: ivocvect.h:46
void add(double fac)
Definition: matrixmap.cpp:20
void alloc(int, int, Node **, int *)
Definition: matrixmap.cpp:40
int nrow()
Definition: matrixmap.h:40
void mulv(Vect &in, Vect &out)
Definition: matrixmap.h:16
int ncol()
Definition: matrixmap.h:43
NEURON Differential Algebraic Equations.
Definition: nrndae.h:27
int size_
total number of states declared or modified in this object
Definition: nrndae.h:174
void v2y()
Transfer any voltage states to y_.
Definition: nrndae.cpp:258
MatrixMap * c_
the matrix
Definition: nrndae.h:162
void rhs()
Compute the right side portion of.
Definition: nrndae.cpp:305
int start_
the position of the first added equation (if any) in the global system
Definition: nrndae.h:186
virtual ~NrnDAE()
Destructor.
Definition: nrndae.cpp:192
int nnode_
Number of voltage nodes used by the dynamics.
Definition: nrndae.h:180
virtual double jacobian_multiplier_()
Definition: nrndae.h:150
Vect cyp_
temporary vector used for residual calculation.
Definition: nrndae.h:189
virtual void f_(Vect &y, Vect &yprime, int size)=0
The right-hand-side function.
void alloc(int start_index)
Allocate space for these dynamics in the overall system.
Definition: nrndae.cpp:108
void lhs()
Compute the left side portion of.
Definition: nrndae.cpp:314
Vect yptmp_
temporary vector used for residual calculation.
Definition: nrndae.h:192
virtual void alloc_(int size, int start, int nnode, Node **nodes, int *elayer)
Additional allocation for subclasses.
Definition: nrndae.cpp:106
void update()
Update states to reflect the changes over a time-step.
Definition: nrndae.cpp:224
void * data_
Data to pass to f_init_.
Definition: nrndae.h:147
NrnDAE(Matrix *cmat, Vect *const yvec, Vect *const y0, int nnode, Node **const nodes, Vect *const elayer, void(*f_init)(void *data)=NULL, void *const data=NULL)
Constructor.
Definition: nrndae.cpp:141
void dkres(double *y, double *yprime, double *delta)
Compute the residual:
Definition: nrndae.cpp:277
int * bmap_
mapping between the states in y and the states in the whole system
Definition: nrndae.h:177
void dkmap(std::vector< double * > &pv, std::vector< double * > &pvdot)
Setup the map between voltages and states in y_.
Definition: nrndae.cpp:214
Matrix * assumed_identity_
identity matrix if constructed with
Definition: nrndae.h:165
Vect * y0_
vector of initial conditions
Definition: nrndae.h:168
Node ** nodes_
Pointers to voltage nodes used by the dynamics.
Definition: nrndae.h:183
void init()
Initialize the dynamics.
Definition: nrndae.cpp:236
virtual MatrixMap * jacobian_(Vect &y)=0
Compute the Jacobian.
Vect & y_
vector to store the state variables in
Definition: nrndae.h:171
int * elayer_
Which voltage layers to read from.
Definition: nrndae.h:201
void(* f_init_)(void *data)
Function used for initializing the state variables.
Definition: nrndae.h:144
int extra_eqn_count()
Find the number of state variables introduced by this object.
Definition: nrndae.cpp:207
#define extnode
Definition: md1redef.h:16
#define i
Definition: md1redef.h:19
#define y_(arg)
Crout matrix decomposition : Forward/Backward substitution.
Definition: crout.hpp:136
#define assert(ex)
Definition: hocassrt.h:24
#define neqn
Definition: lineq.h:3
Item * next(Item *item)
Definition: list.cpp:89
NrnThread * nrn_threads
Definition: multicore.cpp:56
int nrn_nthread
Definition: multicore.cpp:55
bool cvode_active_
Definition: netcvode.cpp:36
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
int nrn_use_daspk_
Definition: treeset.cpp:59
void nrndae_lhs()
Definition: nrndae.cpp:86
void nrndae_dkres(double *y, double *yprime, double *delta)
Definition: nrndae.cpp:98
void nrndae_init()
Definition: nrndae.cpp:56
int nrndae_extra_eqn_count()
Definition: nrndae.cpp:26
void nrndae_rhs(NrnThread *_nt)
Definition: nrndae.cpp:76
static NrnDAEPtrList nrndae_list
Definition: nrndae.cpp:11
int nrndae_list_is_empty()
Definition: nrndae.cpp:13
void nrndae_dkmap(std::vector< double * > &pv, std::vector< double * > &pvdot)
Definition: nrndae.cpp:92
void nrndae_alloc()
Definition: nrndae.cpp:42
void nrndae_update(NrnThread *_nt)
Definition: nrndae.cpp:34
int secondorder
Definition: init.cpp:107
void nrndae_register(NrnDAE *n)
Add a NrnDAE object to the system.
Definition: nrndae.cpp:18
void nrndae_deregister(NrnDAE *n)
Remove a NrnDAE object from the system.
Definition: nrndae.cpp:22
Supports modifying voltage equations and adding new equations.
std::list< NrnDAE * > NrnDAEPtrList
Definition: nrndae.h:221
void nrn_matrix_node_free()
Definition: treeset.cpp:1771
int const size_t const size_t n
Definition: nrngsl.h:10
void nrn_thread_error(const char *s)
Definition: multicore.cpp:297
#define NODEV(n)
Definition: section_fwd.hpp:60
#define nlayer
Definition: section_fwd.hpp:31
#define NULL
Definition: spdefs.h:105
double * v
Definition: section_fwd.hpp:40
int nodecount
Definition: nrnoc_ml.h:78
Definition: section.h:105
int eqn_index_
Definition: section.h:187
Extnode * extnode
Definition: section.h:199
Represent main neuron object computed by single thread.
Definition: multicore.h:58
int end
Definition: multicore.h:65
Memb_list * _ecell_memb_list
Definition: multicore.h:95
double * _sp13_rhs
Definition: multicore.h:92
Definition: hocdec.h:173
void update_actual_d_based_on_sp13_mat(NrnThread *nt)
Definition: treeset.cpp:354
void update_actual_rhs_based_on_sp13_rhs(NrnThread *nt)
Definition: treeset.cpp:336
void update_sp13_rhs_based_on_actual_rhs(NrnThread *nt)
Definition: treeset.cpp:345
void update_sp13_mat_based_on_actual_d(NrnThread *nt)
Definition: treeset.cpp:363