NEURON
impedanc.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #undef check
3 #include "nrnmpi.h"
4 #include "nonlinz.h"
5 #include <InterViews/resource.h>
6 #include <complex>
7 #include "nrnoc2iv.h"
8 #include "classreg.h"
9 #include <ivstream.h>
10 #include <stdio.h>
11 #include "membfunc.h"
12 extern void nrn_rhs(NrnThread*);
13 extern void nrn_lhs(NrnThread*);
14 extern int tree_changed;
15 extern "C" int v_structure_change;
16 extern void setup_topology();
17 extern void recalc_diam();
18 
19 typedef void (*Pfrv4)(int, Node**, double**, Datum**);
20 
21 class Imp {
22 public:
23  Imp() = default;
24  virtual ~Imp();
25  // v(x)/i(x) and v(loc)/i(x) == v(x)/i(loc)
26  int compute(double freq, bool nonlin = false, int maxiter = 500);
27  void location(Section*, double);
28  double transfer_amp(Section*, double);
29  double input_amp(Section*, double);
30  double transfer_phase(Section*, double);
31  double input_phase(Section*, double);
32  double ratio_amp(Section*, double);
33 private:
34  int loc(Section*, double);
35  void alloc();
36  void impfree();
37  void check();
38  void setmat(double);
39  void setmat1();
40 
41  void LUDecomp();
42  void solve();
43 public:
44  double deltafac_ = .001;
45 private:
46  int n = 0;
47  std::complex<double>* transfer = nullptr;
48  std::complex<double>* input = nullptr;
49  std::complex<double>* d = nullptr; /* diagonal */
50  std::complex<double>* pivot = nullptr;
51  int istim = -1; /* where current injected */
52  Section* sloc_ = nullptr;
53  double xloc_ = 0.;
54  NonLinImp* nli_ = nullptr;
55 };
56 
57 static void* cons(Object*) {
58  Imp* imp = new Imp();
59  return (void*)imp;
60 }
61 
62 static void destruct(void* v) {
63  Imp* imp = (Imp*)v;
64  delete imp;
65 }
66 
67 static double compute(void* v) {
68  Imp* imp = (Imp*)v;
69  int rval = 0;
70  bool nonlin = false;
71  if (ifarg(2)) {
72  nonlin = *getarg(2) ? true : false;
73  }
74  if (ifarg(3)) {
75  rval = imp->compute(*getarg(1), nonlin, int(chkarg(3, 1, 1e9)));
76  }else{
77  rval = imp->compute(*getarg(1), nonlin);
78  }
79  return double(rval);
80 }
81 
82 static double location(void* v) {
83  Imp* imp = (Imp*)v;
84  double x;
85  Section* sec = nullptr;
86  if (hoc_is_double_arg(1)) {
87  x = chkarg(1, -1., 1.);
88  if (x >= 0.0) { sec = chk_access(); }
89  }else{
90  nrn_seg_or_x_arg(1, &sec, &x);
91  }
92  imp->location(sec, x);
93  return 0.;
94 }
95 
96 static double transfer_amp(void* v) {
97  Imp* imp = (Imp*)v;
98  double x;
99  Section* sec;
100  nrn_seg_or_x_arg(1, &sec, &x);
101  return imp->transfer_amp(sec, x);
102 }
103 static double input_amp(void* v) {
104  Imp* imp = (Imp*)v;
105  double x;
106  Section* sec;
107  nrn_seg_or_x_arg(1, &sec, &x);
108  return imp->input_amp(sec, x);
109 }
110 static double transfer_phase(void* v) {
111  Imp* imp = (Imp*)v;
112  double x;
113  Section* sec;
114  nrn_seg_or_x_arg(1, &sec, &x);
115  return imp->transfer_phase(sec, x);
116 }
117 static double input_phase(void* v) {
118  Imp* imp = (Imp*)v;
119  double x;
120  Section* sec;
121  nrn_seg_or_x_arg(1, &sec, &x);
122  return imp->input_phase(sec, x);
123 }
124 static double ratio_amp(void* v) {
125  Imp* imp = (Imp*)v;
126  double x;
127  Section* sec;
128  nrn_seg_or_x_arg(1, &sec, &x);
129  return imp->ratio_amp(sec, x);
130 }
131 
132 static double deltafac(void* v) {
133  Imp* imp = (Imp*)v;
134  if (ifarg(1)) {
135  imp->deltafac_ = chkarg(1, 1e-10, 1);
136  }
137  return imp->deltafac_;
138 }
139 
140 static Member_func members[] = {
141  "compute", compute,
142  "loc", location,
143  "input", input_amp,
144  "transfer", transfer_amp,
145  "ratio", ratio_amp,
146  "input_phase", input_phase,
147  "transfer_phase", transfer_phase,
148  "deltafac", deltafac,
149  0, 0
150 };
151 
153  class2oc("Impedance", cons, destruct, members, nullptr, nullptr, nullptr);
154 }
155 
157  if (sloc_) {
159  }
160  impfree();
161 }
162 
164  if (d) {
165  delete [] d;
166  delete [] transfer;
167  delete [] input;
168  delete [] pivot;
169  d = nullptr;
170  }
171  if (nli_) {
172  delete nli_;
173  nli_ = nullptr;
174  }
175 }
176 
177 void Imp::check() {
178  NrnThread* _nt = nrn_threads;
179  nrn_thread_error("Impedance works with only one thread");
180  if (sloc_ && !sloc_->prop) {
182  sloc_ = nullptr;
183  }
184  if (tree_changed) {
185  setup_topology();
186  }
187  if (v_structure_change) {
188  recalc_diam();
189  }
190  if (n != _nt->end) {
191  alloc();
192  }
193 }
194 
195 void Imp::alloc(){
196  NrnThread* _nt = nrn_threads;
197  impfree();
198  n = _nt->end;
199  d = new std::complex<double>[n];
200  transfer = new std::complex<double>[n];
201  input = new std::complex<double>[n];
202  pivot = new std::complex<double>[n];
203 }
204 int Imp::loc(Section* sec, double x){
205  if (x < 0.0 || sec == nullptr) { return -1; }
206  const Node* nd = node_exact(sec, x);
207  return nd->v_node_index;
208 }
209 
210 double Imp::transfer_amp(Section* sec, double x){
211  check();
212  int vloc = loc(sec, x);
213  return nli_ ? nli_->transfer_amp(istim, vloc) : abs(transfer[vloc]);
214 }
215 
216 double Imp::input_amp(Section* sec, double x){
217  check();
218  return nli_ ? nli_->input_amp(loc(sec, x)) : abs(input[loc(sec, x)]);
219 }
220 
221 double Imp::transfer_phase(Section* sec, double x){
222  check();
223  return nli_ ? nli_->transfer_phase(istim, loc(sec, x)) : arg(transfer[loc(sec, x)]);
224 }
225 
226 double Imp::input_phase(Section* sec, double x){
227  check();
228  return nli_ ? nli_->input_phase(loc(sec, x)) : arg(input[loc(sec, x)]);
229 }
230 
231 double Imp::ratio_amp(Section* sec, double x){
232  check();
233  int i = loc(sec, x);
234  return nli_ ? nli_->ratio_amp(i, istim) : (abs(transfer[i]/input[i]));
235 }
236 
237 void Imp::location(Section* sec, double x){
238  if (sloc_) {
240  }
241  sloc_ = sec;
242  xloc_ = x;
243  if (sloc_) {
245  }
246 }
247 
248 int Imp::compute(double freq, bool nonlin, int maxiter){
249  int rval = 0;
250  check();
251  if (sloc_) {
252  istim = loc(sloc_, xloc_);
253  }else{
254  istim = -1;
255  if (nrnmpi_numprocs == 0) {
256  hoc_execerror("Impedance stimulus location is not specified.", 0);
257  }
258  }
259  if (n == 0 && nrnmpi_numprocs == 1) return rval;
260  double omega = 1e-6*2*3.14159265358979323846*freq; // wC has units of mho/cm2
261  if (nonlin) {
262  if (!nli_) {
263  nli_ = new NonLinImp();
264  }
265  nli_->compute(omega, deltafac_, maxiter);
266  rval = nli_->solve(istim);
267  }else{
268  if (nli_) {
269  delete nli_;
270  nli_ = nullptr;
271  }
272  if (istim == -1) {
273  hoc_execerror("Impedance stimulus location is not specified.", 0);
274  }
275  setmat(omega);
276  LUDecomp();
277  solve();
278  }
279  return rval;
280 }
281 
282 void Imp::setmat(double omega) {
283  const NrnThread* _nt = nrn_threads;
284  setmat1();
285  for (int i = 0; i < n; ++i) {
286  d[i] = std::complex<double>(NODED(_nt->_v_node[i]), NODERHS(_nt->_v_node[i]) * omega);
287  transfer[i] = 0.;
288  }
289  transfer[istim] = 1.e2/NODEAREA(_nt->_v_node[istim]); // injecting 1nA
290  // rhs returned is then in units of mV or MegOhms
291 }
292 
293 
294 void Imp::setmat1() {
295  /*
296  The calculated g is good til someone else
297  changes something having to do with the matrix.
298  */
299  const NrnThread* _nt = nrn_threads;
300  const Memb_list* mlc = _nt->tml->ml;
301  assert(_nt->tml->index == CAP);
302  for (int i = 0; i < nrn_nthread; ++i) {
303  double cj = nrn_threads[i].cj;
304  nrn_threads[i].cj = 0;
305  nrn_rhs(nrn_threads+i); // not useful except that many model description set g while
306  // computing i
308  nrn_threads[i].cj = cj;
309  }
310  for (int i = 0; i < n; ++i) {
311  NODERHS(_nt->_v_node[i]) = 0;
312  }
313  for (int i = 0; i < mlc->nodecount; ++i) {
314  NODERHS(mlc->nodelist[i]) = mlc->data[i][0];
315  }
316 }
317 
319  const NrnThread* _nt = nrn_threads;
320  for (int i = _nt->end - 1; i >= _nt->ncell; --i) {
321  int ip = _nt->_v_parent[i]->v_node_index;
322  pivot[i] = NODEA(_nt->_v_node[i]) / d[i];
323  d[ip] -= pivot[i] * NODEB(_nt->_v_node[i]);
324  }
325 }
326 
327 void Imp::solve() {
328  for (int j = 0; j < nrn_nthread; ++j) {
329  const NrnThread* _nt = nrn_threads + j;
330  for (int i=istim; i >= _nt->ncell; --i) {
331  int ip = _nt->_v_parent[i]->v_node_index;
332  transfer[ip] -= transfer[i] * pivot[i];
333  }
334  for (int i = 0; i < _nt->ncell; ++i) {
335  transfer[i] /= d[i];
336  input[i] = 1./d[i];
337  }
338  for (int i = _nt->ncell; i < _nt->end; ++i) {
339  int ip = _nt->_v_parent[i]->v_node_index;
340  transfer[i] -= NODEB(_nt->_v_node[i]) * transfer[ip];
341  transfer[i] /= d[i];
342  input[i] = (std::complex<double>(1) + input[ip]*pivot[i]*NODEB(_nt->_v_node[i]))/d[i];
343  }
344  // take into account area
345  for (int i = _nt->ncell; i < _nt->end; ++i) {
346  input[i] *= 1e2/NODEAREA(_nt->_v_node[i]);
347  }
348  }
349 }
static void destruct(void *v)
Definition: impedanc.cpp:62
int tree_changed
Definition: cabcode.cpp:19
struct Prop * prop
Definition: section.h:62
#define assert(ex)
Definition: hocassrt.h:26
void nrn_rhs(NrnThread *)
Definition: treeset.cpp:355
double transfer_phase(Section *, double)
Definition: impedanc.cpp:221
return true
Definition: savstate.cpp:357
int abs(int)
#define NODED(n)
Definition: section.h:103
int hoc_is_double_arg(int narg)
Definition: code.cpp:733
void
Node ** _v_parent
Definition: multicore.h:78
double input_phase(Section *, double)
Definition: impedanc.cpp:226
Represent main neuron object computed by single thread.
Definition: multicore.h:58
int solve(int curloc)
Definition: nonlinz.cpp:172
Definition: impedanc.cpp:21
void nrn_thread_error(const char *)
Definition: multicore.cpp:453
nd
Definition: treeset.cpp:893
double transfer_amp(int curloc, int vloc)
Definition: nonlinz.cpp:61
#define v
Definition: md1redef.h:4
double ** data
Definition: nrnoc_ml.h:14
void alloc()
Definition: impedanc.cpp:195
double xloc_
Definition: impedanc.cpp:53
double deltafac_
Definition: impedanc.cpp:44
#define e
Definition: passive0.cpp:24
void impfree()
Definition: impedanc.cpp:163
int ncell
Definition: multicore.h:64
static void * cons(Object *)
Definition: impedanc.cpp:57
int nrn_nthread
Definition: multicore.cpp:44
Node ** _v_node
Definition: multicore.h:77
void check()
Definition: impedanc.cpp:177
Memb_list * ml
Definition: multicore.h:35
int nodecount
Definition: nrnoc_ml.h:18
int nrnmpi_numprocs
void LUDecomp()
Definition: impedanc.cpp:318
NrnThread * nrn_threads
Definition: multicore.cpp:45
#define NODEA(n)
Definition: section.h:123
void class2oc(const char *, void *(*cons)(Object *), void(*destruct)(void *), Member_func *, int(*checkpoint)(void **), Member_ret_obj_func *, Member_ret_str_func *)
Definition: hoc_oop.cpp:1581
Section * sloc_
Definition: impedanc.cpp:52
virtual ~Imp()
Definition: impedanc.cpp:156
int
Definition: nrnmusic.cpp:71
Imp()=default
void setmat(double)
Definition: impedanc.cpp:282
static Member_func members[]
Definition: impedanc.cpp:140
std::complex< double > * pivot
Definition: impedanc.cpp:50
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:741
size_t j
inode< _nt-> end
Definition: multicore.cpp:985
void setmat1()
Definition: impedanc.cpp:294
void location(Section *, double)
Definition: impedanc.cpp:237
#define NODEB(n)
Definition: section.h:124
#define CAP
Definition: membfunc.h:64
void setup_topology()
Definition: cabcode.cpp:1736
double transfer_amp(Section *, double)
Definition: impedanc.cpp:210
void recalc_diam()
Definition: treeset.cpp:940
void compute(double omega, double deltafac, int maxiter)
Definition: nonlinz.cpp:125
int ifarg(int)
Definition: code.cpp:1562
int end
Definition: multicore.h:65
void section_ref(Section *)
Definition: solve.cpp:563
double ratio_amp(int clmploc, int vloc)
Definition: nonlinz.cpp:107
double input_amp(int curloc)
Definition: nonlinz.cpp:72
void nrn_seg_or_x_arg(int iarg, Section **psec, double *px)
Definition: point.cpp:191
std::complex< double > * d
Definition: impedanc.cpp:49
#define NODERHS(n)
Definition: section.h:104
NonLinImp * nli_
Definition: impedanc.cpp:54
Node ** nodelist
Definition: nrnoc_ml.h:5
double input_amp(Section *, double)
Definition: impedanc.cpp:216
int v_node_index
Definition: section.h:174
int v_structure_change
Definition: impedanc.cpp:15
Definition: hocdec.h:226
#define getarg
Definition: hocdec.h:15
#define i
Definition: md1redef.h:12
double cj
Definition: multicore.h:61
void Impedance_reg()
Definition: impedanc.cpp:152
sec
Definition: solve.cpp:885
#define arg
Definition: redef.h:28
void solve()
Definition: impedanc.cpp:327
int n
Definition: impedanc.cpp:46
void(* Pfrv4)(int, Node **, double **, Datum **)
Definition: impedanc.cpp:19
void nrn_lhs(NrnThread *)
Definition: treeset.cpp:484
NrnThreadMembList * tml
Definition: multicore.h:62
std::complex< double > * input
Definition: impedanc.cpp:48
double ratio_amp(Section *, double)
Definition: impedanc.cpp:231
void section_unref(Section *)
Definition: solve.cpp:552
Definition: section.h:132
Definition: hocdec.h:176
Section * chk_access(void)
Definition: cabcode.cpp:437
int compute(double freq, bool nonlin=false, int maxiter=500)
Definition: impedanc.cpp:248
double input_phase(int curloc)
Definition: nonlinz.cpp:95
Node * node_exact(Section *sec, double x)
Definition: cabcode.cpp:1956
double chkarg(int, double low, double high)
Definition: code2.cpp:608
int loc(Section *, double)
Definition: impedanc.cpp:204
std::complex< double > * transfer
Definition: impedanc.cpp:47
double transfer_phase(int curloc, int vloc)
Definition: nonlinz.cpp:84
#define NODEAREA(n)
Definition: section.h:115
int istim
Definition: impedanc.cpp:51
static double deltafac(void *v)
Definition: impedanc.cpp:132