This repository was archived by the owner on Mar 20, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy patheion.cpp
More file actions
350 lines (310 loc) · 11.5 KB
/
eion.cpp
File metadata and controls
350 lines (310 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
/*
# =============================================================================
# Copyright (c) 2016 - 2021 Blue Brain Project/EPFL
#
# See top-level LICENSE file for details.
# =============================================================================.
*/
/// THIS FILE IS AUTO GENERATED DONT MODIFY IT.
#include <math.h>
#include <string.h>
#include "coreneuron/coreneuron.hpp"
#include "coreneuron/mpi/nrnmpi.h"
#include "coreneuron/mechanism/membfunc.hpp"
#include "coreneuron/permute/data_layout.hpp"
#include "coreneuron/utils/nrnoc_aux.hpp"
#define _STRIDE _cntml_padded + _iml
namespace coreneuron {
// for each ion it refers to internal concentration, external concentration, and charge,
const int ion_global_map_member_size = 3;
#define nparm 5
static const char* mechanism[] = {/*just a template*/
"0",
"na_ion",
"ena",
"nao",
"nai",
0,
"ina",
"dina_dv_",
0,
0};
void nrn_init_ion(NrnThread*, Memb_list*, int);
void nrn_alloc_ion(double*, Datum*, int);
static int na_ion, k_ion, ca_ion; /* will get type for these special ions */
int nrn_is_ion(int type) {
// Old: commented to remove dependency on memb_func and alloc function
// return (memb_func[type].alloc == ion_alloc);
return (type < nrn_ion_global_map_size // type smaller than largest ion's
&& nrn_ion_global_map[type] != nullptr); // allocated ion charge variables
}
int nrn_ion_global_map_size;
double** nrn_ion_global_map;
#define global_conci(type) nrn_ion_global_map[type][0]
#define global_conco(type) nrn_ion_global_map[type][1]
#define global_charge(type) nrn_ion_global_map[type][2]
double nrn_ion_charge(int type) {
return global_charge(type);
}
void ion_reg(const char* name, double valence) {
char buf[7][50];
#define VAL_SENTINAL -10000.
sprintf(buf[0], "%s_ion", name);
sprintf(buf[1], "e%s", name);
sprintf(buf[2], "%si", name);
sprintf(buf[3], "%so", name);
sprintf(buf[5], "i%s", name);
sprintf(buf[6], "di%s_dv_", name);
for (int i = 0; i < 7; i++) {
mechanism[i + 1] = buf[i];
}
mechanism[5] = nullptr; /* buf[4] not used above */
int mechtype = nrn_get_mechtype(buf[0]);
if (mechtype >= nrn_ion_global_map_size ||
nrn_ion_global_map[mechtype] == nullptr) { // if hasn't yet been allocated
// allocates mem for ion in ion_map and sets null all non-ion types
if (nrn_ion_global_map_size <= mechtype) {
int size = mechtype + 1;
nrn_ion_global_map = (double**) erealloc(nrn_ion_global_map, sizeof(double*) * size);
for (int i = nrn_ion_global_map_size; i < mechtype; i++) {
nrn_ion_global_map[i] = nullptr;
}
nrn_ion_global_map_size = mechtype + 1;
}
nrn_ion_global_map[mechtype] = (double*) emalloc(ion_global_map_member_size *
sizeof(double));
register_mech((const char**) mechanism,
nrn_alloc_ion,
nrn_cur_ion,
(mod_f_t) 0,
(mod_f_t) 0,
(mod_f_t) nrn_init_ion,
-1,
1);
mechtype = nrn_get_mechtype(mechanism[1]);
_nrn_layout_reg(mechtype, SOA_LAYOUT);
hoc_register_prop_size(mechtype, nparm, 1);
hoc_register_dparam_semantics(mechtype, 0, "iontype");
nrn_writes_conc(mechtype, 1);
sprintf(buf[0], "%si0_%s", name, buf[0]);
sprintf(buf[1], "%so0_%s", name, buf[0]);
if (strcmp("na", name) == 0) {
na_ion = mechtype;
global_conci(mechtype) = DEF_nai;
global_conco(mechtype) = DEF_nao;
global_charge(mechtype) = 1.;
} else if (strcmp("k", name) == 0) {
k_ion = mechtype;
global_conci(mechtype) = DEF_ki;
global_conco(mechtype) = DEF_ko;
global_charge(mechtype) = 1.;
} else if (strcmp("ca", name) == 0) {
ca_ion = mechtype;
global_conci(mechtype) = DEF_cai;
global_conco(mechtype) = DEF_cao;
global_charge(mechtype) = 2.;
} else {
global_conci(mechtype) = DEF_ioni;
global_conco(mechtype) = DEF_iono;
global_charge(mechtype) = VAL_SENTINAL;
}
}
double val = global_charge(mechtype);
if (valence != VAL_SENTINAL && val != VAL_SENTINAL && valence != val) {
fprintf(stderr,
"%s ion valence defined differently in\n\
two USEION statements (%g and %g)\n",
buf[0],
valence,
global_charge(mechtype));
nrn_exit(1);
} else if (valence == VAL_SENTINAL && val == VAL_SENTINAL) {
fprintf(stderr,
"%s ion valence must be defined in\n\
the USEION statement of any model using this ion\n",
buf[0]);
nrn_exit(1);
} else if (valence != VAL_SENTINAL) {
global_charge(mechtype) = valence;
}
}
#ifndef CORENRN_USE_LEGACY_UNITS
#define CORENRN_USE_LEGACY_UNITS 0
#endif
#if CORENRN_USE_LEGACY_UNITS == 1
#define FARADAY 96485.309
#define gasconstant 8.3134
#else
#include "coreneuron/nrnoc/nrnunits_modern.h"
#define FARADAY _faraday_codata2018
#define gasconstant _gasconstant_codata2018
#endif
#define ktf (1000. * gasconstant * (celsius + 273.15) / FARADAY)
double nrn_nernst(double ci, double co, double z, double celsius) {
/*printf("nrn_nernst %g %g %g\n", ci, co, z);*/
if (z == 0) {
return 0.;
}
if (ci <= 0.) {
return 1e6;
} else if (co <= 0.) {
return -1e6;
} else {
return ktf / z * log(co / ci);
}
}
nrn_pragma_omp(declare target)
void nrn_wrote_conc(int type,
double* p1,
int p2,
int it,
double** gimap,
double celsius,
int _cntml_padded) {
if (it & 040) {
int _iml = 0;
/* passing _nt to this function causes cray compiler to segfault during compilation
* hence passing _cntml_padded
*/
double* pe = p1 - p2 * _STRIDE;
pe[0] = nrn_nernst(pe[1 * _STRIDE], pe[2 * _STRIDE], gimap[type][2], celsius);
}
}
nrn_pragma_omp(end declare target)
static double efun(double x) {
if (fabs(x) < 1e-4) {
return 1. - x / 2.;
} else {
return x / (exp(x) - 1);
}
}
double nrn_ghk(double v, double ci, double co, double z) {
double temp = z * v / ktf;
double eco = co * efun(temp);
double eci = ci * efun(-temp);
return (.001) * z * FARADAY * (eci - eco);
}
#if VECTORIZE
#define erev pd[0 * _STRIDE] /* From Eion */
#define conci pd[1 * _STRIDE]
#define conco pd[2 * _STRIDE]
#define cur pd[3 * _STRIDE]
#define dcurdv pd[4 * _STRIDE]
/*
handle erev, conci, conc0 "in the right way" according to ion_style
default. See nrn/lib/help/nrnoc.help.
ion_style("name_ion", [c_style, e_style, einit, eadvance, cinit])
ica is assigned
eca is parameter but if conc exists then eca is assigned
if conc is nrnocCONST then eca calculated on finitialize
if conc is STATE then eca calculated on fadvance and conc finitialize
with global nai0, nao0
nernst(ci, co, charge) and ghk(v, ci, co, charge) available to hoc
and models.
*/
#define iontype ppd[0] /* how _AMBIGUOUS is to be handled */
/*the bitmap is
03 concentration unused, nrnocCONST, DEP, STATE
04 initialize concentrations
030 reversal potential unused, nrnocCONST, DEP, STATE
040 initialize reversal potential
0100 calc reversal during fadvance
0200 ci being written by a model
0400 co being written by a model
*/
#define charge global_charge(type)
#define conci0 global_conci(type)
#define conco0 global_conco(type)
double nrn_nernst_coef(int type) {
/* for computing jacobian element dconc'/dconc */
return ktf / charge;
}
/* Must be called prior to any channels which update the currents */
void nrn_cur_ion(NrnThread* nt, Memb_list* ml, int type) {
int _cntml_actual = ml->nodecount;
double* pd;
Datum* ppd;
(void) nt; /* unused */
/*printf("ion_cur %s\n", memb_func[type].sym->name);*/
int _cntml_padded = ml->_nodecount_padded;
pd = ml->data;
ppd = ml->pdata;
nrn_pragma_acc(parallel loop present(
pd [0:_cntml_padded * 5],
nrn_ion_global_map
[0:nrn_ion_global_map_size] [0:ion_global_map_member_size]) if (nt->compute_gpu)
async(nt->stream_id))
nrn_pragma_omp(target teams distribute parallel for simd if(nt->compute_gpu))
for (int _iml = 0; _iml < _cntml_actual; ++_iml) {
dcurdv = 0.;
cur = 0.;
if (iontype & 0100) {
erev = nrn_nernst(conci, conco, charge, celsius);
}
};
}
/* Must be called prior to other models which possibly also initialize
concentrations based on their own states
*/
void nrn_init_ion(NrnThread* nt, Memb_list* ml, int type) {
int _cntml_actual = ml->nodecount;
double* pd;
Datum* ppd;
(void) nt; /* unused */
// skip initialization if restoring from checkpoint
if (_nrn_skip_initmodel == 1) {
return;
}
/*printf("ion_init %s\n", memb_func[type].sym->name);*/
int _cntml_padded = ml->_nodecount_padded;
pd = ml->data;
ppd = ml->pdata;
// There was no async(...) clause in the initial OpenACC implementation, so
// no `nowait` clause has been added to the OpenMP implementation. TODO:
// verify if this can be made asynchronous or if there is a strong reason it
// needs to be like this.
nrn_pragma_acc(parallel loop present(
pd [0:_cntml_padded * 5],
ppd [0:1],
nrn_ion_global_map
[0:nrn_ion_global_map_size] [0:ion_global_map_member_size]) if (nt->compute_gpu))
nrn_pragma_omp(target teams distribute parallel for simd if(nt->compute_gpu))
for (int _iml = 0; _iml < _cntml_actual; ++_iml) {
if (iontype & 04) {
conci = conci0;
conco = conco0;
}
if (iontype & 040) {
erev = nrn_nernst(conci, conco, charge, celsius);
}
}
}
void nrn_alloc_ion(double* p, Datum* ppvar, int _type) {
assert(0);
}
void second_order_cur(NrnThread* _nt, int secondorder) {
int _cntml_padded;
double* pd;
(void) _nt; /* unused */
double* _vec_rhs = _nt->_actual_rhs;
if (secondorder == 2) {
for (NrnThreadMembList* tml = _nt->tml; tml; tml = tml->next)
if (nrn_is_ion(tml->index)) {
Memb_list* ml = tml->ml;
int _cntml_actual = ml->nodecount;
int* ni = ml->nodeindices;
_cntml_padded = ml->_nodecount_padded;
pd = ml->data;
nrn_pragma_acc(parallel loop present(pd [0:_cntml_padded * 5],
ni [0:_cntml_actual],
_vec_rhs [0:_nt->end]) if (_nt->compute_gpu)
async(_nt->stream_id))
nrn_pragma_omp(target teams distribute parallel for simd if(_nt->compute_gpu))
for (int _iml = 0; _iml < _cntml_actual; ++_iml) {
cur += dcurdv * (_vec_rhs[ni[_iml]]);
}
}
}
}
} // namespace coreneuron
#endif