NEURON
functabl.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 #include "hocdec.h"
4 #include "oc_ansi.h"
5 
6 struct TableArg {
7  int nsize;
8  double* argvec; /* if nullptr use min,max */
9  double min;
10  double max;
11  double frac; /* temporary storage */
12 };
13 
14 struct FuncTable {
15  double* table;
17  double value; /* if constant this is it */
18 };
19 
20 static int arg_index(TableArg* ta, double x) {
21  int j;
22 
23  if (ta->argvec) {
24  ta->frac = 0.;
25  int t0 = 0;
26  int t1 = ta->nsize - 1;
27  if (x <= ta->argvec[t0]) {
28  j = 0;
29  } else if (x >= ta->argvec[t1]) {
30  j = t1;
31  } else {
32  while (t0 < (t1 - 1)) {
33  j = (t0 + t1) / 2;
34  if (ta->argvec[j] <= x) {
35  t0 = j;
36  } else {
37  t1 = j;
38  }
39  }
40  j = t0;
41  ta->frac = (x - ta->argvec[j]) / (ta->argvec[j + 1] - ta->argvec[j]);
42  }
43  } else {
44  ta->frac = 0.;
45  if (x <= ta->min) {
46  j = 0;
47  } else if (x >= ta->max) {
48  j = ta->nsize - 1;
49  } else {
50  double d = (ta->max - ta->min) / ((double) (ta->nsize - 1));
51  double x1 = (x - ta->min) / d;
52  j = (int) x1;
53  ta->frac = x1 - (double) j;
54  }
55  }
56  return j;
57 }
58 
59 static double inter(double frac, double* tab, int j) {
60  if (frac > 0.) {
61  return (1. - frac) * tab[j] + frac * tab[j + 1];
62  } else {
63  return tab[j];
64  }
65 }
66 
67 static double interp(double frac, double x1, double x2) {
68  if (frac > 0.) {
69  return (1. - frac) * x1 + frac * x2;
70  } else {
71  return x1;
72  }
73 }
74 
75 double hoc_func_table(void* vpft, int n, double* args) {
76  auto* const ft = static_cast<FuncTable*>(vpft);
77  if (!ft) {
78  hoc_execerror("table not specified in hoc_func_table", nullptr);
79  }
80  if (ft->value && ft->targs[0].nsize == 1) {
81  return ft->value;
82  }
83  double* tab = ft->table;
84  int j = 0;
85  // matrix order is row order.
86  // I.e. [irow][jcol] is at location irow*ncol + jcol
87  for (size_t i = 0; i < n; ++i) {
88  j = (j * ft->targs[i].nsize) + arg_index(ft->targs + i, args[i]);
89  }
90  if (n == 1) {
91  return inter(ft->targs[0].frac, tab, j);
92  } else if (n == 2) {
93  double fy = ft->targs[1].frac;
94  double y1 = inter(fy, tab, j);
95  if (ft->targs[0].frac) { /* x dimension fraction */
96  int j1 = j + ft->targs[1].nsize;
97  double y2 = inter(fy, tab, j1);
98  return interp(ft->targs[0].frac, y1, y2);
99  } else {
100  return y1;
101  }
102  } else {
103  return tab[j];
104  }
105 }
106 
107 void hoc_spec_table(void** vppt, int n) {
108  auto ppt = reinterpret_cast<FuncTable**>(vppt);
109  if (!*ppt) {
110  *ppt = (FuncTable*) ecalloc(1, sizeof(FuncTable));
111  (*ppt)->targs = (TableArg*) ecalloc(n, sizeof(TableArg));
112  }
113  FuncTable* ft = *ppt;
114  TableArg* ta = ft->targs;
115  if (!ifarg(2)) { /* set to constant */
116  ft->value = *getarg(1);
117  ft->table = &ft->value;
118  for (size_t i = 0; i < n; ++i) {
119  ta[i].nsize = 1;
120  ta[i].argvec = nullptr;
121  ta[i].min = 1e20;
122  ta[i].max = 1e20;
123  }
124  return;
125  }
126  if (hoc_is_object_arg(1) && hoc_is_object_arg(2)) {
127  if (n > 1) {
128  hoc_execerror("Vector arguments allowed only for functions", "of one variable");
129  }
130  Object* ob1 = *hoc_objgetarg(1);
131  hoc_obj_ref(ob1);
132  Object* ob2 = *hoc_objgetarg(2);
133  hoc_obj_ref(ob2);
134  int ns = vector_arg_px(1, &ft->table);
135  ta[0].nsize = vector_arg_px(2, &ta[0].argvec);
136  if (ns != ta[0].nsize) {
137  hoc_execerror("Vector arguments not same size", nullptr);
138  }
139  } else {
140  if (hoc_is_object_arg(1)) {
141  Object* ob1 = *hoc_objgetarg(1);
142  hoc_obj_ref(ob1);
143  }
144  ft->table = hoc_pgetarg(1);
145  int argcnt = 2;
146  for (size_t i = 0; i < n; ++i) {
147  ta[i].nsize = *getarg(argcnt++);
148  if (ta[i].nsize < 1) {
149  hoc_execerror("size arg < 1 in hoc_spec_table", nullptr);
150  }
151  if (hoc_is_double_arg(argcnt)) {
152  ta[i].min = *getarg(argcnt++);
153  ta[i].max = *getarg(argcnt++);
154  if (ta[i].max < ta[i].min) {
155  hoc_execerror("min > max in hoc_spec_table", nullptr);
156  }
157  ta[i].argvec = nullptr;
158  } else {
159  if (hoc_is_object_arg(argcnt)) {
160  Object* ob1 = *hoc_objgetarg(argcnt);
161  hoc_obj_ref(ob1);
162  }
163  ta[i].argvec = hoc_pgetarg(argcnt++);
164  }
165  }
166  }
167 }
#define i
Definition: md1redef.h:19
static double inter(double frac, double *tab, int j)
Definition: functabl.cpp:59
static double interp(double frac, double x1, double x2)
Definition: functabl.cpp:67
static int arg_index(TableArg *ta, double x)
Definition: functabl.cpp:20
int hoc_is_object_arg(int narg)
Definition: code.cpp:876
double hoc_func_table(void *vpft, int n, double *args)
Definition: functabl.cpp:75
int vector_arg_px(int, double **)
Definition: ivocvect.cpp:396
void hoc_spec_table(void **vppt, int n)
Definition: functabl.cpp:107
int hoc_is_double_arg(int narg)
Definition: code.cpp:864
void hoc_obj_ref(Object *obj)
Definition: hoc_oop.cpp:1844
double * hoc_pgetarg(int narg)
Definition: oc_ansi.h:253
#define getarg
Definition: hocdec.h:17
Object ** hoc_objgetarg(int)
Definition: code.cpp:1614
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
void * ecalloc(size_t n, size_t size)
Definition: nrnoc_aux.cpp:85
int const size_t const size_t n
Definition: nrngsl.h:10
size_t j
int ifarg(int)
Definition: code.cpp:1607
HOC interpreter function declarations (included by hocdec.h)
double * table
Definition: functabl.cpp:15
TableArg * targs
Definition: functabl.cpp:16
double value
Definition: functabl.cpp:17
Definition: hocdec.h:173
double min
Definition: functabl.cpp:9
double max
Definition: functabl.cpp:10
int nsize
Definition: functabl.cpp:7
double * argvec
Definition: functabl.cpp:8
double frac
Definition: functabl.cpp:11