Skip to content
This repository was archived by the owner on Mar 20, 2023. It is now read-only.

Commit dbb8ce9

Browse files
authored
Added support for euler (similar to recent thread safe support in NEURON) (#68)
* Added support for euler (similar to thread safe support in NEURON) - updated kinderiv.py to generate - added euler_thread from neuron (updated for aos/soa layout) - mod2c module updated * Renaming and minor changes for euler support: - _derivimplic changed to _derivimplicit - _cb changed to newton - _NRN_EULER_CASES switch case added * Added some notes and todos
1 parent 4cf570a commit dbb8ce9

File tree

4 files changed

+76
-18
lines changed

4 files changed

+76
-18
lines changed

coreneuron/kinderiv.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#!/usr/bin/python
22

33
# read the translated mod files and construct _kinderiv.h
4+
# this is implemented to avoid function callbacks using
5+
# function pointers while using methods like euler, newton
6+
# or kinetic schemes. This is required for GPU implementation.
47

58
# if _kinderiv.h already exists and is the same as what this script generates
69
# then do not update it (to avoid re-compiling all the mech c files if
@@ -12,17 +15,21 @@
1215
import os
1316

1417
fnames = [f.replace('.mod', '.c') for f in os.listdir('.') if f.endswith('.mod')]
18+
euler = []
1519
deriv = []
1620
kin = []
21+
1722
for fname in fnames:
1823
f = open(fname, "r")
1924
for line in f:
2025
word = line.split()
2126
if len(word) > 3:
22-
if word[0] == '/*' and word[1] == '_derivimplic_':
27+
if word[0] == '/*' and word[1] == '_derivimplicit_':
2328
deriv.append([word[2], word[3], fname, word[1]])
2429
if word[0] == '/*' and word[1] == '_kinetic_':
2530
kin.append([word[2], word[3], fname, word[1]])
31+
if word[0] == '/*' and word[1] == '_euler_':
32+
euler.append([word[2], word[3], fname, word[1]])
2633
f.close()
2734

2835
fout = open(kftmp, "w")
@@ -32,7 +39,7 @@
3239
''')
3340

3441
fout.write("\n/* data used to construct this file */\n")
35-
for l in [deriv, kin]:
42+
for l in [deriv, kin, euler]:
3643
for item in l:
3744
fout.write('/*')
3845
for word in item:
@@ -44,7 +51,7 @@
4451
fout.write('#pragma acc routine seq\n')
4552
fout.write('extern int %s%s(_threadargsproto_);\n' % (item[0], item[1]))
4653
fout.write('#pragma acc routine seq\n')
47-
fout.write('extern int _cb_%s%s(_threadargsproto_);\n' % (item[0], item[1]))
54+
fout.write('extern int _newton_%s%s(_threadargsproto_);\n' % (item[0], item[1]))
4855

4956
for item in kin:
5057
fout.write('#pragma acc routine seq\n')
@@ -53,27 +60,35 @@
5360
fout.write("\n/* callback indices */\n")
5461
derivoffset = 1
5562
kinoffset = 1
63+
5664
for i, item in enumerate(deriv):
57-
fout.write('#define _derivimplic_%s%s %d\n' % (item[0], item[1], i + derivoffset))
65+
fout.write('#define _derivimplicit_%s%s %d\n' % (item[0], item[1], i + derivoffset))
5866
for i, item in enumerate(kin):
5967
fout.write('#define _kinetic_%s%s %d\n' % (item[0], item[1], i + kinoffset))
68+
for i, item in enumerate(euler):
69+
fout.write('#define _euler_%s%s %d\n' % (item[0], item[1], i + derivoffset))
6070

6171
fout.write("\n/* switch cases */\n")
62-
fout.write("\n#define _NRN_DERIVIMPLIC_CASES \\\n")
63-
for item in deriv:
64-
fout.write(" case _derivimplic_%s%s: %s%s(_threadargs_); break; \\\n" % (item[0], item[1], item[0], item[1]))
72+
fout.write("\n#define _NRN_DERIVIMPLICIT_CASES \\\n")
73+
for item in (deriv):
74+
fout.write(" case _derivimplicit_%s%s: %s%s(_threadargs_); break; \\\n" % (item[0], item[1], item[0], item[1]))
6575
fout.write("\n")
6676

67-
fout.write("\n#define _NRN_DERIVIMPLIC_CB_CASES \\\n")
77+
fout.write("\n#define _NRN_DERIVIMPLICIT_NEWTON_CASES \\\n")
6878
for item in deriv:
69-
fout.write(" case _derivimplic_%s%s: _cb_%s%s(_threadargs_); break; \\\n" % (item[0], item[1], item[0], item[1]))
79+
fout.write(" case _derivimplicit_%s%s: _newton_%s%s(_threadargs_); break; \\\n" % (item[0], item[1], item[0], item[1]))
7080
fout.write("\n")
7181

7282
fout.write("\n#define _NRN_KINETIC_CASES \\\n")
7383
for item in kin:
7484
fout.write(" case _kinetic_%s%s: %s%s(so, rhs, _threadargs_); break; \\\n" % (item[0], item[1], item[0], item[1]))
7585
fout.write("\n")
7686

87+
fout.write("\n#define _NRN_EULER_CASES \\\n")
88+
for item in euler:
89+
fout.write(" case _euler_%s%s: %s%s(_threadargs_); break; \\\n" % (item[0], item[1], item[0], item[1]))
90+
fout.write("\n")
91+
7792
fout.write('\n#endif\n')
7893
fout.close()
7994

coreneuron/mech/mod2c_core_thread.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,25 @@ typedef int (*SPFUN)(struct SparseObj*, double*, _threadargsproto_);
3737

3838
#else
3939

40+
/**
41+
* \todo: typedefs like DIFUN can be removed
42+
* \todo: macros for difun, newtfun, eulerfun are not necessary
43+
* and need to be refactored.
44+
*/
45+
4046
typedef int DIFUN;
4147
typedef int NEWTFUN;
4248
typedef int SPFUN;
49+
typedef int EULFUN;
4350
#pragma acc routine seq
44-
extern int nrn_derivimplic_steer(int, _threadargsproto_);
45-
#define difun(arg) nrn_derivimplic_steer(arg, _threadargs_);
51+
extern int nrn_derivimplicit_steer(int, _threadargsproto_);
52+
#define difun(arg) nrn_derivimplicit_steer(arg, _threadargs_);
4653
#pragma acc routine seq
4754
extern int nrn_newton_steer(int, _threadargsproto_);
4855
#define newtfun(arg) nrn_newton_steer(arg, _threadargs_);
56+
#pragma acc routine seq
57+
extern int nrn_euler_steer(int, _threadargsproto_);
58+
#define eulerfun(arg) nrn_euler_steer(arg, _threadargs_);
4959

5060
#endif
5161

@@ -97,6 +107,8 @@ typedef struct SparseObj { /* all the state information */
97107
extern int nrn_kinetic_steer(int, SparseObj*, double*, _threadargsproto_);
98108
#define spfun(arg1, arg2, arg3) nrn_kinetic_steer(arg1, arg2, arg3, _threadargs_);
99109

110+
#pragma acc routine seq
111+
extern int euler_thread(int, int*, int*, EULFUN, _threadargsproto_);
100112
#pragma acc routine seq
101113
extern int derivimplicit_thread(int, int*, int*, DIFUN, _threadargsproto_);
102114
#pragma acc routine seq

coreneuron/scopmath_core/dimplic.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1-
/*
2-
hopefully a temporary expedient to work around the inability to
3-
pass function pointers as arguments
1+
/** When we use solve methods like euler, newton or kinetic schemes,
2+
* the state/current updates function need to call solver methods
3+
* defined in coreneuron. This is typically done via function pointers.
4+
* But for GPU implementation using OpenACC, we can't pass function
5+
* pointers.The temporary "workaround" for this was to generate
6+
* switch case to select the proper callback function. This is implemented
7+
* using python script that look into translated file and generate
8+
* _kinderiv.h which has cases for steer functions defined below.
9+
* This allows OpenACC to select gpu implementations at compile
10+
* time.
11+
* \todo: eulerfun/difun are legacy macros and can be replaced with
12+
* actual steer function for euler/derivimplicit methods.
413
*/
514

615
#include "coreneuron/mech/cfile/scoplib.h"
@@ -12,17 +21,39 @@ int derivimplicit_thread(int n, int* slist, int* dlist, DIFUN fun, _threadargspr
1221
return 0;
1322
}
1423

15-
int nrn_derivimplic_steer(int fun, _threadargsproto_) {
16-
switch (fun) { _NRN_DERIVIMPLIC_CASES }
24+
int nrn_derivimplicit_steer(int fun, _threadargsproto_) {
25+
switch (fun) { _NRN_DERIVIMPLICIT_CASES }
26+
return 0;
27+
}
28+
29+
int nrn_euler_steer(int fun, _threadargsproto_) {
30+
switch (fun) { _NRN_EULER_CASES }
1731
return 0;
1832
}
1933

2034
int nrn_newton_steer(int fun, _threadargsproto_) {
21-
switch (fun) { _NRN_DERIVIMPLIC_CB_CASES }
35+
switch (fun) { _NRN_DERIVIMPLICIT_NEWTON_CASES }
2236
return 0;
2337
}
2438

2539
int nrn_kinetic_steer(int fun, SparseObj* so, double* rhs, _threadargsproto_) {
2640
switch (fun) { _NRN_KINETIC_CASES }
2741
return 0;
2842
}
43+
44+
// derived from nrn/src/scopmath/euler.c
45+
// updated for aos/soa layout index
46+
int euler_thread(int neqn, int* var, int* der, DIFUN fun, _threadargsproto_) {
47+
48+
double dt = _nt->_dt;
49+
int i;
50+
51+
/* calculate the derivatives */
52+
eulerfun(fun);
53+
54+
/* update dependent variables */
55+
for (i = 0; i < neqn; i++)
56+
_p[var[i]*_STRIDE] += dt * (_p[der[i]*_STRIDE]);
57+
58+
return 0;
59+
}

0 commit comments

Comments
 (0)