NEURON
treeset_core.cpp
Go to the documentation of this file.
1 /*
2 # =============================================================================
3 # Copyright (c) 2016 - 2021 Blue Brain Project/EPFL
4 #
5 # See top-level LICENSE file for details.
6 # =============================================================================.
7 */
8 
9 #include <string>
10 
11 #include "coreneuron/nrnconf.h"
16 
17 namespace coreneuron {
18 /*
19 Fixed step method with threads and cache efficiency. No extracellular,
20 sparse matrix, multisplit, or legacy features.
21 */
22 
23 static void nrn_rhs(NrnThread* _nt) {
24  int i1 = 0;
25  int i2 = i1 + _nt->ncell;
26  int i3 = _nt->end;
27 
28  double* vec_rhs = &(VEC_RHS(0));
29  double* vec_d = &(VEC_D(0));
30  double* vec_a = &(VEC_A(0));
31  double* vec_b = &(VEC_B(0));
32  double* vec_v = &(VEC_V(0));
33  int* parent_index = _nt->_v_parent_index;
34 
35  nrn_pragma_acc(parallel loop present(vec_rhs [0:i3], vec_d [0:i3]) if (_nt->compute_gpu)
36  async(_nt->stream_id))
37  nrn_pragma_omp(target teams distribute parallel for if(_nt->compute_gpu))
38  for (int i = i1; i < i3; ++i) {
39  vec_rhs[i] = 0.;
40  vec_d[i] = 0.;
41  }
42 
43  if (_nt->nrn_fast_imem) {
44  double* fast_imem_d = _nt->nrn_fast_imem->nrn_sav_d;
45  double* fast_imem_rhs = _nt->nrn_fast_imem->nrn_sav_rhs;
47  parallel loop present(fast_imem_d [i1:i3], fast_imem_rhs [i1:i3]) if (_nt->compute_gpu)
48  async(_nt->stream_id))
49  nrn_pragma_omp(target teams distribute parallel for if(_nt->compute_gpu))
50  for (int i = i1; i < i3; ++i) {
51  fast_imem_d[i] = 0.;
52  fast_imem_rhs[i] = 0.;
53  }
54  }
55 
57  /* note that CAP has no current */
58  for (auto tml = _nt->tml; tml; tml = tml->next)
59  if (corenrn.get_memb_func(tml->index).current) {
60  mod_f_t s = corenrn.get_memb_func(tml->index).current;
61  std::string ss("cur-");
62  ss += nrn_get_mechname(tml->index);
63  Instrumentor::phase p(ss.c_str());
64  (*s)(_nt, tml->ml, tml->index);
65 #ifdef DEBUG
66  if (errno) {
67  hoc_warning("errno set during calculation of currents", nullptr);
68  }
69 #endif
70  }
71 
72  if (_nt->nrn_fast_imem) {
73  /* nrn_sav_rhs has only the contribution of electrode current
74  here we transform so it only has membrane current contribution
75  */
76  double* p = _nt->nrn_fast_imem->nrn_sav_rhs;
77  nrn_pragma_acc(parallel loop present(p, vec_rhs) if (_nt->compute_gpu)
78  async(_nt->stream_id))
79  nrn_pragma_omp(target teams distribute parallel for if(_nt->compute_gpu))
80  for (int i = i1; i < i3; ++i) {
81  p[i] -= vec_rhs[i];
82  }
83  }
84 
85  /* now the internal axial currents.
86  The extracellular mechanism contribution is already done.
87  rhs += ai_j*(vi_j - vi)
88  */
89  nrn_pragma_acc(parallel loop present(vec_rhs [0:i3],
90  vec_d [0:i3],
91  vec_a [0:i3],
92  vec_b [0:i3],
93  vec_v [0:i3],
94  parent_index [0:i3]) if (_nt->compute_gpu)
95  async(_nt->stream_id))
96  nrn_pragma_omp(target teams distribute parallel for if(_nt->compute_gpu))
97  for (int i = i2; i < i3; ++i) {
98  double dv = vec_v[parent_index[i]] - vec_v[i];
99  /* our connection coefficients are negative so */
100  nrn_pragma_acc(atomic update)
101  nrn_pragma_omp(atomic update)
102  vec_rhs[i] -= vec_b[i] * dv;
103  nrn_pragma_acc(atomic update)
104  nrn_pragma_omp(atomic update)
105  vec_rhs[parent_index[i]] += vec_a[i] * dv;
106  }
107 }
108 
109 /* calculate left hand side of
110 cm*dvm/dt = -i(vm) + is(vi) + ai_j*(vi_j - vi)
111 cx*dvx/dt - cm*dvm/dt = -gx*(vx - ex) + i(vm) + ax_j*(vx_j - vx)
112 with a matrix so that the solution is of the form [dvm+dvx,dvx] on the right
113 hand side after solving.
114 This is a common operation for fixed step, cvode, and daspk methods
115 */
116 
117 static void nrn_lhs(NrnThread* _nt) {
118  int i1 = 0;
119  int i2 = i1 + _nt->ncell;
120  int i3 = _nt->end;
121 
122  /* note that CAP has no jacob */
123  for (auto tml = _nt->tml; tml; tml = tml->next)
124  if (corenrn.get_memb_func(tml->index).jacob) {
125  mod_f_t s = corenrn.get_memb_func(tml->index).jacob;
126  std::string ss("cur-");
127  ss += nrn_get_mechname(tml->index);
128  Instrumentor::phase p(ss.c_str());
129  (*s)(_nt, tml->ml, tml->index);
130 #ifdef DEBUG
131  if (errno) {
132  hoc_warning("errno set during calculation of jacobian", (char*) 0);
133  }
134 #endif
135  }
136  /* now the cap current can be computed because any change to cm by another model
137  has taken effect
138  */
139  /* note, the first is CAP if there are any nodes*/
140  if (_nt->end && _nt->tml) {
141  assert(_nt->tml->index == CAP);
142  nrn_jacob_capacitance(_nt, _nt->tml->ml, _nt->tml->index);
143  }
144 
145  double* vec_d = &(VEC_D(0));
146  double* vec_a = &(VEC_A(0));
147  double* vec_b = &(VEC_B(0));
148  int* parent_index = _nt->_v_parent_index;
149 
150  if (_nt->nrn_fast_imem) {
151  /* nrn_sav_d has only the contribution of electrode current
152  here we transform so it only has membrane current contribution
153  */
154  double* p = _nt->nrn_fast_imem->nrn_sav_d;
155  nrn_pragma_acc(parallel loop present(p, vec_d) if (_nt->compute_gpu) async(_nt->stream_id))
156  nrn_pragma_omp(target teams distribute parallel for if(_nt->compute_gpu))
157  for (int i = i1; i < i3; ++i) {
158  p[i] = vec_d[i] - p[i];
159  }
160  }
161 
162  /* now add the axial currents */
163  nrn_pragma_acc(parallel loop present(
164  vec_d [0:i3], vec_a [0:i3], vec_b [0:i3], parent_index [0:i3]) if (_nt->compute_gpu)
165  async(_nt->stream_id))
166  nrn_pragma_omp(target teams distribute parallel for if(_nt->compute_gpu))
167  for (int i = i2; i < i3; ++i) {
168  nrn_pragma_acc(atomic update)
169  nrn_pragma_omp(atomic update)
170  vec_d[i] -= vec_b[i];
171  nrn_pragma_acc(atomic update)
172  nrn_pragma_omp(atomic update)
173  vec_d[parent_index[i]] -= vec_a[i];
174  }
175 }
176 
177 /* for the fixed step method */
179  nrn_rhs(_nt);
180  nrn_lhs(_nt);
181  return nullptr;
182 }
183 } // namespace coreneuron
auto & get_memb_func(size_t idx)
Definition: coreneuron.hpp:135
#define i
Definition: md1redef.h:19
nrn_pragma_acc(routine seq) nrn_pragma_omp(declare target) philox4x32_ctr_t coreneuron_random123_philox4x32_helper(coreneuron nrn_pragma_omp(end declare target) namespace coreneuron
Provide a helper function in global namespace that is declared target for OpenMP offloading to functi...
Definition: nrnran123.h:66
#define assert(ex)
Definition: hocassrt.h:24
#define CAP
Definition: membfunc.hpp:60
#define BEFORE_BREAKPOINT
Definition: membfunc.hpp:69
THIS FILE IS AUTO GENERATED DONT MODIFY IT.
void(*)(NrnThread *, Memb_list *, int) mod_f_t
Definition: membfunc.hpp:24
void update(NrnThread *_nt)
static void nrn_lhs(NrnThread *_nt)
const char * nrn_get_mechname(int type)
Definition: mk_mech.cpp:152
void * setup_tree_matrix_minimal(NrnThread *)
CoreNeuron corenrn
Definition: multicore.cpp:53
static void nrn_rhs(NrnThread *_nt)
nrn_pragma_acc(routine seq) int vector_capacity(void *v)
Definition: ivocvect.cpp:30
void nrn_jacob_capacitance(NrnThread *, Memb_list *, int)
Definition: capac.cpp:55
void hoc_warning(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:44
void nrn_ba(NrnThread *nt, int bat)
auto *const vec_d
Definition: cellorder.cpp:615
auto *const vec_b
Definition: cellorder.cpp:614
auto *const vec_rhs
Definition: cellorder.cpp:616
#define VEC_D(i)
Definition: nrnconf.h:29
#define VEC_B(i)
Definition: nrnconf.h:28
#define VEC_RHS(i)
Definition: nrnconf.h:30
#define VEC_A(i)
Definition: nrnconf.h:27
#define VEC_V(i)
Definition: nrnconf.h:31
size_t p
s
Definition: multisend.cpp:521
NrnFastImem * nrn_fast_imem
Definition: multicore.hpp:124
NrnThreadMembList * tml
Definition: multicore.hpp:80
NrnThreadMembList * next
Definition: multicore.hpp:33