NEURON
membfunc.h
Go to the documentation of this file.
1 #pragma once
2 extern void hoc_register_prop_size(int type, int psize, int dpsize);
3 
5 #include "nrnoc_ml.h"
6 #include "oc_ansi.h" // neuron::model_sorted_token
7 #include "options.h" // EXTRACELLULAR
8 #include "ion_semantics.h"
9 
10 #include <string>
11 #include <type_traits>
12 #include <vector>
13 #include <unordered_map>
14 
15 typedef struct NrnThread NrnThread;
16 struct Extnode;
17 struct Section;
18 struct Symbol;
19 
20 typedef Datum* (*Pfrpdat)();
21 typedef void (*Pvmi)(struct NrnThread*, Memb_list*, int);
22 typedef void (*Pvmp)(Prop*);
23 typedef int (*nrn_ode_count_t)(int);
24 using nrn_bamech_t = void (*)(Node*,
25  Datum*,
26  Datum*,
27  NrnThread*,
28  Memb_list*,
29  std::size_t,
31 using nrn_cur_t = void (*)(neuron::model_sorted_token const&, NrnThread*, Memb_list*, int);
34 using nrn_ode_map_t = void (*)(Prop*,
35  int /* ieq */,
36  neuron::container::data_handle<double>* /* pv (std::span) */,
37  neuron::container::data_handle<double>* /* pvdot (std::span) */,
38  double* /* atol */,
39  int /* type */);
45  std::size_t,
46  Datum*,
47  Datum*,
48  double*,
49  NrnThread*,
50  int,
52 
53 #define NULL_CUR (Pfri) 0
54 #define NULL_ALLOC (Pfri) 0
55 #define NULL_STATE (Pfri) 0
56 #define NULL_INITIALIZE (Pfri) 0
57 
58 struct Memb_func {
63  bool has_initialize() const {
64  return m_initialize;
65  }
66  void invoke_initialize(neuron::model_sorted_token const& sorted_token,
67  NrnThread* nt,
68  Memb_list* ml,
69  int type) const;
72  }
73  Pvmp destructor; /* only for point processes */
80  Pvmi singchan_; /* managed by kschan for variable step methods */
82  int thread_size_; /* how many Datum needed in Memb_list if vectorized */
83  void (*thread_mem_init_)(Datum*); /* after Memb_list._thread is allocated */
84  void (*thread_cleanup_)(Datum*); /* before Memb_list._thread is freed */
86  int is_point;
87  void* hoc_mech;
88  void (*setdata_)(struct Prop*);
89  std::unique_ptr<int[]> dparam_semantics; // for nrncore writing.
90  const std::vector<double>* parm_default; // for NrnProperty
91  private:
93 };
94 
95 /* Direct call Python wrappers to density mechanism functions */
97  const char* name;
98  double (*func)(Prop*);
99 };
100 /* Above struct in translated mod files are elements of a {nullptr, nullptr}
101  terminated list. The translator could easily create an unordered map instead,
102  and that would be nicer.
103  However there is some question (as with std::string) that an unordered_map
104  is ABI compatible across codes compiled by different toolchains.
105  So we will build our per mechanism map in NEURON world from the null
106  terminated list in NMODL world.
107 */
108 using NPyDirectMechFuncs = std::unordered_map<std::string, NPyDirectMechFunc*>;
110 extern std::unordered_map<int, NPyDirectMechFuncs> nrn_mech2funcs_map;
111 
112 extern void hoc_register_parm_default(int type, const std::vector<double>*);
113 
114 #define IMEMFAST -2
115 #define VINDEX -1
116 #define CABLESECTION 1
117 #define MORPHOLOGY 2
118 #define CAP 3
119 #if EXTRACELLULAR
120 #define EXTRACELL 5
121 extern int nrn_nlayer_extracellular;
123 // these are the fields in the standard NEURON mechanism data structures
124 static constexpr auto xraxial_index = 0; // array of size nlayer
125 static constexpr auto xg_index = 1; // array of size nlayer
126 static constexpr auto xc_index = 2; // array of size nlayer
127 static constexpr auto e_extracellular_index = 3; // scalar
128 static constexpr auto i_membrane_index = 4; // scalar, might not exist
129 static constexpr auto sav_g_index = 5; // scalar, might not exist
130 static constexpr auto sav_rhs_index = 6; // scalar, might not exist
131 
132 // these are the indices into the Extnode param array
133 inline std::size_t xraxial_index_ext(std::size_t ilayer) {
134  return ilayer;
135 }
136 inline std::size_t xg_index_ext(std::size_t ilayer) {
137  return nrn_nlayer_extracellular + ilayer;
138 }
139 inline std::size_t xc_index_ext(std::size_t ilayer) {
140  return 2 * nrn_nlayer_extracellular + ilayer;
141 }
142 inline std::size_t e_extracellular_index_ext() {
143  return 3 * nrn_nlayer_extracellular;
144 }
145 #if I_MEMBRANE
146 inline std::size_t sav_rhs_index_ext() {
147  return 3 * nrn_nlayer_extracellular + 3;
148 }
149 #endif
150 inline std::size_t vext_pseudoindex() {
151 #if I_MEMBRANE
152  return 3 * nrn_nlayer_extracellular + 4;
153 #else
154  return 3 * nrn_nlayer_extracellular + 1;
155 #endif
156 }
157 } // namespace neuron::extracellular
158 #endif
159 
160 #define nrnocCONST 1 // PARAMETER
161 #define DEP 2 // ASSIGNED
162 #define STATE 3 /* STATE: See init.cpp and cabvars.h for order of nrnocCONST, DEP, and STATE */
163 #define NRNPOINTER \
164  4 /* added on to list of mechanism variables.These are \
165 pointers which connect variables from other mechanisms via the _ppval array. \
166 */
167 
168 #define _AMBIGUOUS 5 // for Ions
169 #define NMODLRANDOM 6 // RANDOM variable in NEURON block
170 
171 #define BEFORE_INITIAL 0
172 #define AFTER_INITIAL 1
173 #define BEFORE_BREAKPOINT 2
174 #define AFTER_SOLVE 3
175 #define BEFORE_STEP 4
176 #define BEFORE_AFTER_SIZE 5 /* 1 more than the previous */
177 typedef struct BAMech {
179  int type;
180  struct BAMech* next;
181 } BAMech;
182 extern BAMech** bamech_;
183 
184 extern std::vector<Memb_func> memb_func;
185 extern int n_memb_func;
186 extern int* nrn_prop_param_size_;
187 extern int* nrn_prop_dparam_size_;
188 extern int nrn_dparam_semantics_to_int(const char*);
189 extern std::vector<int>& nrn_mech_random_indices(int type);
190 
191 extern std::vector<Memb_list> memb_list;
192 /* for finitialize, order is same up through extracellular, then ions,
193 then mechanisms that write concentrations, then all others. */
194 extern short* memb_order_;
195 
196 namespace neuron::mechanism {
197 template <typename T>
198 struct field {
199  using type = T;
200  field(std::string name_)
201  : name{std::move(name_)} {}
202  field(std::string name_, int array_size_)
203  : name{std::move(name_)}
204  , array_size{array_size_} {}
205  field(std::string name_, std::string semantics_)
206  : name{std::move(name_)}
207  , semantics{std::move(semantics_)} {}
208  int array_size{1};
209  std::string name{}, semantics{};
210 };
211 namespace detail {
213  std::vector<std::pair<const char*, int>> const& param_info,
214  std::vector<std::pair<const char*, const char*>> const& dparam_size);
216  std::vector<std::pair<std::string, int>> const& param_info,
217  std::vector<std::pair<std::string, std::string>> const& dparam_size);
218 } // namespace detail
219 /**
220  * @brief Type- and array-aware version of hoc_register_prop_size.
221  *
222  * hoc_register_prop_size did not propagate enough information to know which parts of the "data"
223  * size were ranges corresponding to a single array variable. This also aims to be ready for
224  * supporting multiple variable data types in MOD files.
225  */
226 // This is declared static on purpose. When we are using binary Python wheels and a user runs
227 // nrnivmodl on their local machine then we link together a libnrniv.so from the binary wheel
228 // with object files that were produced from .mod files on the user's machine. If the files
229 // compiled on the user's machine have the same number/type of variables as a built in mechanism
230 // that is embedded in libnrniv.so then there will be two calls to this function with the same
231 // template arguments. If this function was not static, those would have external linkage and a
232 // call from one of the user's .mod files might use a definition of this function from
233 // libnrniv.so. This can cause problems due to ABI mismatches, and the ::detail version above
234 // essentially exists to ensure that *it* is the interface between libnrniv.so and code compiled
235 // on the user's machine. Yes, this is horrible. See #1963 and #2234 for more information.
236 template <typename... Fields>
237 static void register_data_fields(int mech_type, Fields const&... fields) {
238  // Use of const char* aims to avoid wheel ABI issues with std::string
239  std::vector<std::pair<const char*, int>> param_info{};
240  std::vector<std::pair<const char*, const char*>> dparam_info{};
241  auto const process = [&](auto const& field) {
242  using field_t = std::decay_t<decltype(field)>;
243  using data_t = typename field_t::type;
244  if constexpr (std::is_same_v<data_t, double>) {
245  assert(field.semantics.empty());
246  param_info.emplace_back(field.name.c_str(), field.array_size);
247  } else {
248  static_assert(std::is_same_v<data_t, int> /* TODO */ || std::is_pointer_v<data_t>,
249  "only pointers, doubles and ints are supported");
250  assert(field.array_size == 1); // only scalar dparam data is supported
251  dparam_info.emplace_back(field.name.c_str(), field.semantics.c_str());
252  }
253  };
254  // fold expression with the comma operator is neater, but hits AppleClang expression depth
255  // limits for large sizeof...(Fields); the old initializer_list trick avoids that.
256  static_cast<void>(std::initializer_list<int>{(static_cast<void>(process(fields)), 0)...});
257  // beware, the next call crosses from translated mechanism code into the main NEURON library
258  detail::register_data_fields(mech_type, param_info, dparam_info);
259 }
260 
261 /**
262  * @brief Get the number of fields (some of which may be arrays) of the given type.
263  *
264  * If the given mechanism type is negative, -1 will be returned.
265  */
266 template <typename>
267 [[nodiscard]] int get_field_count(int mech_type);
268 
269 /**
270  * @brief Pointer to a range of pointers to the start of contiguous storage ranges.
271  *
272  * If the given mechanism type is negative, nullptr will be returned.
273  */
274 template <typename T>
275 [[nodiscard]] T* const* get_data_ptrs(int mech_type);
276 
277 /**
278  * @brief Get the array dimensions for fields of the given type.
279  *
280  * This forms part of the API used by translated MOD file code to access the
281  * mechanism data managed by NEURON. It serves to help hide the implementation
282  * of the mechanism data storage from translated MOD file code and reduce ABI
283  * compatibility issues arising from Python wheel support.
284  *
285  * If the given mechanism type is negative, nullptr will be returned.
286  */
287 template <typename>
288 [[nodiscard]] int const* get_array_dims(int mech_type);
289 namespace _get {
290 [[nodiscard]] std::size_t _current_row(Prop*);
291 [[nodiscard]] std::vector<double* const*> const& _pdata_ptr_cache_data(
292  neuron::model_sorted_token const& cache_token,
293  int mech_type);
294 } // namespace _get
295 } // namespace neuron::mechanism
296 
297 // See https://github.com/neuronsimulator/nrn/issues/2234 for context of how this might be done
298 // better in future...
299 [[nodiscard]] long& _nrn_mechanism_access_alloc_seq(Prop*);
300 [[nodiscard]] Node* _nrn_mechanism_access_node(Prop* prop);
301 [[nodiscard]] double& _nrn_mechanism_access_a(Node*);
302 [[nodiscard]] double& _nrn_mechanism_access_b(Node*);
303 [[nodiscard]] double& _nrn_mechanism_access_d(Node*);
305 [[nodiscard]] Extnode*& _nrn_mechanism_access_extnode(Node*);
306 [[nodiscard]] double& _nrn_mechanism_access_param(Prop*, int field, int array_index = 0);
307 [[nodiscard]] double& _nrn_mechanism_access_rhs(Node*);
308 [[nodiscard]] double& _nrn_mechanism_access_voltage(Node*);
310 [[nodiscard]] Section* _nrn_mechanism_get_child(Section*);
311 [[nodiscard]] int _nrn_mechanism_get_nnode(Section*);
312 [[nodiscard]] Node* _nrn_mechanism_get_node(Section*, int);
313 [[nodiscard]] int _nrn_mechanism_get_num_vars(Prop*);
315  Prop* prop,
317 [[nodiscard]] inline neuron::container::data_handle<double>
318 _nrn_mechanism_get_param_handle(Prop* prop, int field, int array_index = 0) {
320  neuron::container::field_index{field, array_index});
321 }
323 [[nodiscard]] NrnThread* _nrn_mechanism_get_thread(Node*);
324 [[nodiscard]] int _nrn_mechanism_get_type(Prop*);
325 [[nodiscard]] int _nrn_mechanism_get_v_node_index(Node*);
326 
327 // Rarely (e.g. NEURON {RANDOM123 ranvar}) instances of a mod file
328 // need to deallocate owning objects at end of their life.
329 extern std::unordered_map<int, void (*)(Prop*)> nrn_mech_inst_destruct;
#define prop
Definition: md1redef.h:38
#define assert(ex)
Definition: hocassrt.h:24
void hoc_register_parm_default(int type, const std::vector< double > *)
Definition: init.cpp:741
struct BAMech BAMech
void(*)(Prop *, int, neuron::container::data_handle< double > *, neuron::container::data_handle< double > *, double *, int) nrn_ode_map_t
Definition: membfunc.h:39
int nrn_dparam_semantics_to_int(const char *)
Definition: init.cpp:984
int _nrn_mechanism_get_nnode(Section *)
Definition: membfunc.cpp:62
neuron::container::data_handle< double > _nrn_mechanism_get_param_handle(Prop *prop, neuron::container::field_index field)
Definition: membfunc.cpp:71
int nrn_nlayer_extracellular
Definition: extcelln.cpp:16
void(*)(Memb_list *, std::size_t, Datum *, Datum *, double *, NrnThread *, int, neuron::model_sorted_token const &) nrn_thread_table_check_t
Definition: membfunc.h:51
NrnThread * _nrn_mechanism_get_thread(Node *)
Definition: membfunc.cpp:76
std::vector< Memb_list > memb_list
Definition: init.cpp:146
std::vector< Memb_func > memb_func
Definition: init.cpp:145
void(* Pvmp)(Prop *)
Definition: membfunc.h:22
void hoc_register_prop_size(int type, int psize, int dpsize)
Legacy way of registering mechanism data/pdata size.
Definition: init.cpp:970
double & _nrn_mechanism_access_rhs(Node *)
Definition: membfunc.cpp:46
double & _nrn_mechanism_access_d(Node *)
Definition: membfunc.cpp:34
int(* nrn_ode_count_t)(int)
Definition: membfunc.h:23
void(* Pvmi)(struct NrnThread *, Memb_list *, int)
Definition: membfunc.h:21
int _nrn_mechanism_get_type(Prop *)
Definition: membfunc.cpp:82
Extnode *& _nrn_mechanism_access_extnode(Node *)
Definition: membfunc.cpp:40
nrn_cur_t nrn_ode_spec_t
Definition: membfunc.h:41
double & _nrn_mechanism_access_a(Node *)
Definition: membfunc.cpp:28
std::unordered_map< int, NPyDirectMechFuncs > nrn_mech2funcs_map
Definition: init.cpp:963
long & _nrn_mechanism_access_alloc_seq(Prop *)
Definition: membfunc.cpp:20
int * nrn_prop_param_size_
Definition: init.cpp:162
neuron::container::generic_data_handle *& _nrn_mechanism_access_dparam(Prop *)
Definition: membfunc.cpp:37
void hoc_register_npy_direct(int type, NPyDirectMechFunc *)
Support mechanism FUNCTION/PROCEDURE python syntax seg.mech.f()
Definition: init.cpp:957
Node * _nrn_mechanism_get_node(Section *, int)
Definition: membfunc.cpp:65
double & _nrn_mechanism_access_voltage(Node *)
Definition: membfunc.cpp:49
int _nrn_mechanism_get_v_node_index(Node *)
Definition: membfunc.cpp:85
nrn_cur_t nrn_state_t
Definition: membfunc.h:43
double & _nrn_mechanism_access_param(Prop *, int field, int array_index=0)
Definition: membfunc.cpp:43
std::vector< int > & nrn_mech_random_indices(int type)
dparam indices with random semantics for mechtype
Definition: init.cpp:991
BAMech ** bamech_
Definition: init.cpp:151
nrn_cur_t nrn_init_t
Definition: membfunc.h:32
Section * _nrn_mechanism_get_child(Section *)
Definition: membfunc.cpp:59
int * nrn_prop_dparam_size_
Definition: init.cpp:163
double & _nrn_mechanism_access_b(Node *)
Definition: membfunc.cpp:31
void(*)(neuron::model_sorted_token const &, NrnThread *, Memb_list *, int) nrn_cur_t
Definition: membfunc.h:31
std::unordered_map< int, void(*)(Prop *)> nrn_mech_inst_destruct
Definition: init.cpp:167
neuron::container::data_handle< double > _nrn_mechanism_get_area_handle(Node *)
Definition: membfunc.cpp:52
Section * _nrn_mechanism_get_sibling(Section *)
Definition: membfunc.cpp:79
Node * _nrn_mechanism_access_node(Prop *prop)
Definition: membfunc.cpp:24
nrn_cur_t nrn_ode_matsol_t
Definition: membfunc.h:40
nrn_cur_t nrn_jacob_t
Definition: membfunc.h:33
std::unordered_map< std::string, NPyDirectMechFunc * > NPyDirectMechFuncs
Definition: membfunc.h:108
short * memb_order_
Definition: init.cpp:147
int _nrn_mechanism_get_num_vars(Prop *)
Definition: membfunc.cpp:68
void(*)(Node *, Datum *, Datum *, NrnThread *, Memb_list *, std::size_t, neuron::model_sorted_token const &) nrn_bamech_t
Definition: membfunc.h:30
void(*)(neuron::model_sorted_token const &, NrnThread &, Memb_list &, int) nrn_ode_synonym_t
Definition: membfunc.h:42
int n_memb_func
Definition: init.cpp:448
void init()
Definition: init.cpp:141
void move(Item *q1, Item *q2, Item *q3)
Definition: list.cpp:200
std::size_t e_extracellular_index_ext()
Definition: membfunc.h:142
static constexpr auto xraxial_index
Definition: membfunc.h:124
std::size_t sav_rhs_index_ext()
Definition: membfunc.h:146
static constexpr auto e_extracellular_index
Definition: membfunc.h:127
std::size_t xg_index_ext(std::size_t ilayer)
Definition: membfunc.h:136
static constexpr auto xg_index
Definition: membfunc.h:125
static constexpr auto xc_index
Definition: membfunc.h:126
std::size_t vext_pseudoindex()
Definition: membfunc.h:150
static constexpr auto sav_rhs_index
Definition: membfunc.h:130
static constexpr auto sav_g_index
Definition: membfunc.h:129
static constexpr auto i_membrane_index
Definition: membfunc.h:128
std::size_t xc_index_ext(std::size_t ilayer)
Definition: membfunc.h:139
std::size_t xraxial_index_ext(std::size_t ilayer)
Definition: membfunc.h:133
std::vector< double *const * > const & _pdata_ptr_cache_data(neuron::model_sorted_token const &cache_token, int mech_type)
Definition: membfunc.cpp:96
std::size_t _current_row(Prop *prop)
Definition: membfunc.cpp:93
void register_data_fields(int mechtype, std::vector< std::pair< std::string, int >> const &param_info, std::vector< std::pair< std::string, std::string >> const &dparam_info)
Definition: init.cpp:851
static void register_data_fields(int mech_type, Fields const &... fields)
Type- and array-aware version of hoc_register_prop_size.
Definition: membfunc.h:235
int const * get_array_dims(int mech_type)
Get the array dimensions for fields of the given type.
T *const * get_data_ptrs(int mech_type)
Pointer to a range of pointers to the start of contiguous storage ranges.
int get_field_count(int mech_type)
Get the number of fields (some of which may be arrays) of the given type.
mech_type
short type
Definition: cabvars.h:10
HOC interpreter function declarations (included by hocdec.h)
struct BAMech * next
Definition: membfunc.h:178
nrn_bamech_t f
Definition: membfunc.h:176
int type
Definition: membfunc.h:177
void * hoc_mech
Definition: membfunc.h:87
nrn_ode_spec_t ode_spec
Definition: membfunc.h:77
int is_point
Definition: membfunc.h:86
nrn_ode_synonym_t ode_synonym
Definition: membfunc.h:79
void(* setdata_)(struct Prop *)
Definition: membfunc.h:88
nrn_jacob_t jacob
Definition: membfunc.h:61
const std::vector< double > * parm_default
Definition: membfunc.h:90
int thread_size_
Definition: membfunc.h:82
nrn_ode_map_t ode_map
Definition: membfunc.h:76
Pvmp alloc
Definition: membfunc.h:59
int vectorized
Definition: membfunc.h:81
void invoke_initialize(neuron::model_sorted_token const &sorted_token, NrnThread *nt, Memb_list *ml, int type) const
Definition: membfunc.cpp:8
nrn_ode_count_t ode_count
Definition: membfunc.h:75
bool has_initialize() const
Definition: membfunc.h:63
Pvmp destructor
Definition: membfunc.h:73
void set_initialize(nrn_init_t init)
Definition: membfunc.h:70
nrn_thread_table_check_t thread_table_check_
Definition: membfunc.h:85
void(* thread_mem_init_)(Datum *)
Definition: membfunc.h:83
nrn_cur_t current
Definition: membfunc.h:60
void(* thread_cleanup_)(Datum *)
Definition: membfunc.h:84
nrn_init_t m_initialize
Definition: membfunc.h:92
Symbol * sym
Definition: membfunc.h:74
Pvmi singchan_
Definition: membfunc.h:80
std::unique_ptr< int[]> dparam_semantics
Definition: membfunc.h:89
nrn_ode_matsol_t ode_matsol
Definition: membfunc.h:78
nrn_state_t state
Definition: membfunc.h:62
A view into a set of mechanism instances.
Definition: nrnoc_ml.h:34
double(* func)(Prop *)
Definition: membfunc.h:98
const char * name
Definition: membfunc.h:97
Definition: section.h:105
Represent main neuron object computed by single thread.
Definition: multicore.h:58
Definition: section.h:231
Definition: model.h:47
Struct used to index SoAoS data, such as array range variables.
Non-template stable handle to a generic value.
std::string semantics
Definition: membfunc.h:207
field(std::string name_)
Definition: membfunc.h:198
field(std::string name_, int array_size_)
Definition: membfunc.h:200