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