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) {
55  neqn += _nt -> _ecell_memb_list -> nodecount * nlayer;
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 
103 void NrnDAE::alloc(int start_index) {
104 //printf("NrnDAE::alloc %lx\n", (long)this);
105  size_ = y_.size();
106  if (y0_) {
107  assert(y0_ -> size() == size_);
108  }
109  assert(c_->nrow() == size_ && c_->ncol() == size_);
110  cyp_.resize(size_);
111  yptmp_.resize(size_);
112  start_ = start_index;
113 //printf("start=%d size=%d\n", start_, size_);
114  delete [] bmap_;
115  bmap_ = new int[size_];
116  for (int i = 0; i < size_; ++i) {
117  if (i < nnode_) {
118  bmap_[i] = nodes_[i]->eqn_index_ + elayer_[i];
119  if (elayer_[i] > 0 && !nodes_[i]->extnode) {
120 //hoc_execerror(secname(nodes_[i]->sec), "NrnDAE: Referring to an extracellular 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
132  alloc_(size_, start_, nnode_, nodes_, elayer_);
133 }
134 
135 NrnDAE::NrnDAE(Matrix* cmat, Vect* const yvec, Vect* const y0, int nnode,
136  Node** const nodes, Vect* const elayer, void (*f_init)(void* data), void* const data)
137  : y_(*yvec), yptmp_((Object*) NULL), cyp_((Object*) NULL), f_init_(f_init), data_(data) {
138 //printf("NrnDAE %lx\n", (long)this);
139  if (cmat) {
141  } else {
142  const int size = y_.size();
143  assumed_identity_ = new OcSparseMatrix(size, size);
144  //assumed_identity_->setdiag(0, 1);
145  for (int i = 0; i < size; i++) (*assumed_identity_)(i, i) = 1;
146  cmat = assumed_identity_;
147  }
148  c_ = new MatrixMap(cmat);
149  Vect &elay = *elayer;
150  nnode_ = nnode;
151  nodes_ = nodes;
152  if (nnode_ > 0) {
153  elayer_ = new int[nnode_];
154  if (elayer) {
155  for (int i = 0; i < nnode_; ++i) {
156  elayer_[i] = int(elay[i]);
157  }
158  } else {
159  for (int i = 0; i < nnode_; ++i) {
160  elayer_[i] = 0;
161  }
162  }
163  } else {
164  elayer_ = NULL;
165  }
166  y0_ = y0;
167  bmap_ = new int[1];
168 
169  nrndae_register(this);
170 // use_sparse13 = 1;
172 }
173 
174 
176  nrndae_deregister(this);
177  delete [] bmap_;
178  delete c_;
179  delete assumed_identity_;
180  if (elayer_) {
181  delete [] elayer_;
182  }
183 // if (nrndae_list->count() == 0) {
184 // use_sparse13 = 0;
185 // }
187 }
188 
189 
191 //printf("NrnDAE::extra_eqn_count %lx\n", (long)this);
192 //printf(" nnode_=%d g_->nrow()=%d\n", nnode_, g_->nrow());
193  return c_->nrow() - nnode_;
194 }
195 
196 void NrnDAE::dkmap(double** pv, double** pvdot) {
197  //printf("NrnDAE::dkmap\n");
198  NrnThread* _nt = nrn_threads;
199  for (int i = nnode_; i < size_; ++i) {
200 //printf("bmap_[%d] = %d\n", i, bmap_[i]);
201  pv[bmap_[i] - 1] = y_.data() + i;
202  pvdot[bmap_[i] - 1] = _nt->_actual_rhs + bmap_[i];
203  }
204 }
205 
207 //printf("NrnDAE::update %lx\n", (long)this);
208  NrnThread* _nt = nrn_threads;
209  // note that the following is correct also for states that refer
210  // to the internal potential of a segment. i.e rhs is v + vext[0]
211  for (int i = 0; i < size_; ++i) {
212  y_[i] += _nt->_actual_rhs[bmap_[i]];
213  }
214 //for (int i=0; i < size_; ++i) printf(" i=%d bmap_[i]=%d y_[i]=%g\n", i, bmap_[i], y_->elem(i));
215 }
216 
217 void NrnDAE::init() {
218 //printf("NrnDAE::init %lx\n", (long)this);
219 //printf("init size_=%d %d %d %d\n", size_, y_->size(), y0_->size(), b_->size());
220  Vect& y0 = *y0_;
221 
222  v2y();
223  if (f_init_) {
224  f_init_(data_);
225  } else {
226  if (y0_) {
227  for (int i = nnode_; i < size_; ++i) {
228  y_[i] = y0[i];
229  }
230  } else {
231  for (int i = nnode_; i < size_; ++i) {
232  y_[i] = 0.;
233  }
234  }
235  }
236 //for (i=0; i < nnode_; ++i) printf(" i=%d y[i]=%g\n", i, y[i]);
237 }
238 
239 void NrnDAE::v2y() {
240  // vm,vext may be reinitialized between fixed steps and certainly
241  // have been adjusted by daspk
242 
243  for (int i = 0; i < nnode_; ++i) {
244  Node* nd = nodes_[i];
245  //Note elayer_[0] refers to internal.
246  if (elayer_[i] == 0) {
247  y_[i] = NODEV(nd);
248  if (nd -> extnode) {
249  y_[i] += nd->extnode->v[0];
250  }
251  } else if (nd -> extnode) {
252  y_[i] = nd -> extnode -> v[elayer_[i] - 1];
253  }
254  }
255 }
256 
257 
258 
259 void NrnDAE::dkres(double* y, double* yprime, double* delta) {
260 //printf("NrnDAE::dkres %lx\n", (long)this);
261  // delta is already f(y)
262  // now subtract c*y'
263  // The problem is the map between y and yprime and the local
264  // representation of the y and yprime
265 
266  for (int i = 0; i < size_; ++i) {
267 //printf("%d %d %g %g\n", i, bmap_[i]-1, y[bmap_[i]-1], yprime[bmap_[i]-1]);
268  yptmp_[i] = yprime[bmap_[i] - 1];
269  }
270  Vect* cyp;
271  if (assumed_identity_) {
272  // if c_ is KNOWN to be the identity matrix, then no multiplication to do
273  // for now, this happens only when cmat = NULL
274  // note that the user might change cmat, so we can't assume that if it's initially
275  // the identity that it will stay that way
276  cyp = &yptmp_;
277  } else {
278  c_->mulv(yptmp_, cyp_); // mulv cannot multiply in place
279  cyp = &cyp_;
280  }
281  for (int i = 0; i < size_; ++i) {
282  delta[bmap_[i] - 1] -= (*cyp)[i];
283  }
284 }
285 
286 
287 void NrnDAE::rhs() {
288  NrnThread* _nt = nrn_threads;
289  v2y();
290  f_(y_, yptmp_, size_);
291  for (int i = 0; i < size_; ++i) {
292  _nt->_actual_rhs[bmap_[i]] += yptmp_[i];
293  }
294 }
295 
296 void NrnDAE::lhs() {
297 //printf("NrnDAE::lhs %lx\n", (long)this);
298 //printf(" nrn_threads[0].cj = %g\n", nrn_threads[0].cj);
299  //left side portion of (c/dt - J)*[dy] = f(y)
300  c_->add(nrn_threads[0].cj);
301  v2y();
303 }
304 
305 
int cvode_active_
Definition: fadvance.cpp:158
#define data
Definition: rbtqueue.cpp:49
void init()
Initialize the dynamics.
Definition: nrndae.cpp:217
void dkres(double *y, double *yprime, double *delta)
Compute the residual: .
Definition: nrndae.cpp:259
double * v
Definition: section.h:195
#define assert(ex)
Definition: hocassrt.h:26
void nrndae_register(NrnDAE *n)
Add a NrnDAE object to the system.
Definition: nrndae.cpp:28
void alloc(int start_index)
Allocate space for these dynamics in the overall system.
Definition: nrndae.cpp:103
#define NODEV(n)
Definition: section.h:114
#define Vect
Definition: ivocvect.h:14
Vect yptmp_
temporary vector used for residual calculation.
Definition: nrndae.h:186
int nrndae_extra_eqn_count()
Definition: nrndae.cpp:36
Vect & y_
vector to store the state variables in
Definition: nrndae.h:165
int nrndae_list_is_empty()
Definition: nrndae.cpp:23
Represent main neuron object computed by single thread.
Definition: multicore.h:58
int secondorder
Definition: init.cpp:120
double * _actual_rhs
Definition: multicore.h:70
void v2y()
Transfer any voltage states to y_.
Definition: nrndae.cpp:239
static void update(NrnThread *)
Definition: fadvance.cpp:570
NrnDAEPtrList::const_iterator NrnDAEPtrListIterator
Definition: nrndae.h:216
void nrn_thread_error(const char *)
Definition: multicore.cpp:453
nd
Definition: treeset.cpp:893
MatrixMap * c_
the matrix
Definition: nrndae.h:156
void add(double fac)
Definition: matrixmap.cpp:29
#define v
Definition: md1redef.h:4
void nrndae_rhs()
Definition: nrndae.cpp:74
void rhs()
Compute the right side portion of .
Definition: nrndae.cpp:287
Node ** nodes_
Pointers to voltage nodes used by the dynamics.
Definition: nrndae.h:177
int nrn_use_daspk_
Definition: treeset.cpp:70
virtual ~NrnDAE()
Destructor.
Definition: nrndae.cpp:175
j< sec-> nnode
Definition: treeset.cpp:905
void start()
Definition: hel2mos.cpp:205
Supports modifying voltage equations and adding new equations.
void dkmap(double **pv, double **pvdot)
Setup the map between voltages and states in y_.
Definition: nrndae.cpp:196
void alloc(int, int, Node **, int *)
Definition: matrixmap.cpp:36
void init()
Definition: init.cpp:169
#define extnode
Definition: md1redef.h:9
void nrndae_alloc()
Definition: nrndae.cpp:50
int extra_eqn_count()
Find the number of state variables introduced by this object.
Definition: nrndae.cpp:190
int const size_t const size_t n
Definition: nrngsl.h:12
virtual void alloc_(int size, int start, int nnode, Node **nodes, int *elayer)
Additional allocation for subclasses.
Definition: nrndae.cpp:100
Memb_list * _ecell_memb_list
Definition: multicore.h:80
void * data_
Data to pass to f_init_.
Definition: nrndae.h:142
NrnThread * nrn_threads
Definition: multicore.cpp:45
static NrnDAEPtrList nrndae_list
Definition: nrndae.cpp:21
std::list< NrnDAE * > NrnDAEPtrList
Definition: nrndae.h:215
virtual void f_(Vect &y, Vect &yprime, int size)=0
The right-hand-side function.
void nrn_matrix_node_free()
Definition: treeset.cpp:1901
int
Definition: nrnmusic.cpp:71
virtual double jacobian_multiplier_()
Definition: nrndae.h:145
int nnode_
Number of voltage nodes used by the dynamics.
Definition: nrndae.h:174
void nrndae_init()
Definition: nrndae.cpp:64
int * bmap_
mapping between the states in y and the states in the whole system
Definition: nrndae.h:171
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:741
void update()
Update states to reflect the changes over a time-step.
Definition: nrndae.cpp:206
Vect * y0_
vector of initial conditions
Definition: nrndae.h:162
inode< _nt-> end
Definition: multicore.cpp:985
void nrndae_dkmap(double **, double **)
Definition: nrndae.cpp:86
int ncol()
Definition: matrixmap.h:30
#define nlayer
Definition: section.h:187
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
#define rhs
Definition: lineq.h:6
NEURON Differential Algebraic Equations.
Definition: nrndae.h:27
void nrndae_update()
Definition: nrndae.cpp:44
void nrndae_dkpsol(double)
int nrow()
Definition: matrixmap.h:29
int start_
the position of the first added equation (if any) in the global system
Definition: nrndae.h:180
Vect cyp_
temporary vector used for residual calculation.
Definition: nrndae.h:183
int * elayer_
Which voltage layers to read from.
Definition: nrndae.h:195
Definition: hocdec.h:226
void nrndae_deregister(NrnDAE *n)
Remove a NrnDAE object from the system.
Definition: nrndae.cpp:32
#define nodecount
Definition: md1redef.h:30
#define i
Definition: md1redef.h:12
void nrndae_dkres(double *, double *, double *)
Definition: nrndae.cpp:92
#define neqn
Definition: lineq.h:3
double cj
Definition: multicore.h:61
virtual MatrixMap * jacobian_(Vect &y)=0
Compute the Jacobian.
void nrndae_lhs()
Definition: nrndae.cpp:80
static Symbol * pv[4]
Definition: partial.cpp:80
Matrix * assumed_identity_
identity matrix if constructed with NULL; else NULL.
Definition: nrndae.h:159
Definition: section.h:132
int eqn_index_
Definition: section.h:148
void mulv(Vect &in, Vect &out)
Definition: matrixmap.h:21
return NULL
Definition: cabcode.cpp:461
MatrixPtr Matrix
Definition: sputils.c:601
struct Extnode * extnode
Definition: section.h:160
void(* f_init_)(void *data)
Function used for initializing the state variables.
Definition: nrndae.h:139
void lhs()
Compute the left side portion of .
Definition: nrndae.cpp:296
int size_
total number of states declared or modified in this object
Definition: nrndae.h:168